@revealui/ai 0.10.1 → 1.0.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/README.md +10 -10
- package/dist/client/hooks/useAgentStream.d.ts +2 -0
- package/dist/client/hooks/useAgentStream.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/llm/artifact-provenance.d.ts +73 -0
- package/dist/llm/artifact-provenance.d.ts.map +1 -0
- package/dist/llm/artifact-provenance.js +189 -0
- package/dist/llm/cache-utils.d.ts +0 -9
- package/dist/llm/cache-utils.d.ts.map +1 -1
- package/dist/llm/cache-utils.js +0 -17
- package/dist/llm/client.d.ts +16 -9
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +113 -61
- package/dist/llm/inference-route.d.ts +46 -0
- package/dist/llm/inference-route.d.ts.map +1 -0
- package/dist/llm/inference-route.js +154 -0
- package/dist/llm/local-ai-profile.d.ts.map +1 -1
- package/dist/llm/local-ai-profile.js +3 -3
- package/dist/llm/providers/groq.d.ts +1 -1
- package/dist/llm/providers/groq.d.ts.map +1 -1
- package/dist/llm/providers/groq.js +6 -3
- package/dist/llm/providers/inference-snaps.d.ts +6 -5
- package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
- package/dist/llm/providers/inference-snaps.js +6 -5
- package/dist/llm/providers/ollama.d.ts +1 -1
- package/dist/llm/providers/ollama.d.ts.map +1 -1
- package/dist/llm/providers/ollama.js +3 -2
- package/dist/llm/providers/us-origin-snaps.d.ts +21 -11
- package/dist/llm/providers/us-origin-snaps.d.ts.map +1 -1
- package/dist/llm/providers/us-origin-snaps.js +23 -13
- package/dist/llm/resolve.d.ts.map +1 -1
- package/dist/llm/resolve.js +9 -2
- package/dist/llm/token-counter.d.ts.map +1 -1
- package/dist/llm/token-counter.js +4 -1
- package/dist/llm/tool-json-schema.d.ts +16 -0
- package/dist/llm/tool-json-schema.d.ts.map +1 -0
- package/dist/llm/tool-json-schema.js +64 -0
- package/dist/llm/workspace-provider-config.d.ts.map +1 -1
- package/dist/llm/workspace-provider-config.js +9 -2
- package/dist/orchestration/runtime.d.ts +3 -17
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +4 -15
- package/dist/orchestration/streaming-runtime.d.ts.map +1 -1
- package/dist/orchestration/streaming-runtime.js +2 -2
- package/dist/tools/admin/factory.d.ts +6 -0
- package/dist/tools/admin/factory.d.ts.map +1 -1
- package/dist/tools/admin/factory.js +6 -1
- package/dist/tools/admin/user-tools.js +2 -2
- package/dist/tools/mcp-adapter.d.ts +10 -94
- package/dist/tools/mcp-adapter.d.ts.map +1 -1
- package/dist/tools/mcp-adapter.js +10 -146
- package/dist/tools/mcp-sampling.d.ts +3 -3
- package/dist/tools/mcp-sampling.js +3 -3
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +2 -1
- package/package.json +29 -4
package/dist/llm/client.js
CHANGED
|
@@ -10,6 +10,7 @@ import { decryptApiKey } from '@revealui/db/crypto';
|
|
|
10
10
|
import { tenantProviderConfigs, userApiKeys } from '@revealui/db/schema';
|
|
11
11
|
import { CircuitBreaker, CircuitBreakerOpenError, } from '@revealui/resilience';
|
|
12
12
|
import { and, eq } from 'drizzle-orm';
|
|
13
|
+
import { defaultBaseURLForProvider, defaultModelForProvider, isGroqCatalogModel, resolveInferenceRoute, } from './inference-route.js';
|
|
13
14
|
import { applyLocalAiProfileToEnv } from './local-ai-profile.js';
|
|
14
15
|
import { AnthropicProvider } from './providers/anthropic.js';
|
|
15
16
|
import { GroqProvider } from './providers/groq.js';
|
|
@@ -17,11 +18,10 @@ import { InferenceSnapsProvider, } from './providers/inference-snaps.js';
|
|
|
17
18
|
import { OllamaProvider } from './providers/ollama.js';
|
|
18
19
|
import { OpenAIProvider } from './providers/openai.js';
|
|
19
20
|
import { OpenAICompatProvider } from './providers/openai-compat.js';
|
|
20
|
-
import { DEFAULT_US_ORIGIN_INFERENCE_SNAP } from './providers/us-origin-snaps.js';
|
|
21
21
|
import { XaiProvider } from './providers/xai.js';
|
|
22
22
|
import { ResponseCache } from './response-cache.js';
|
|
23
|
-
import { SemanticCache, } from './semantic-cache.js';
|
|
24
23
|
import { estimateRequest as _estimateRequestTokens } from './token-counter.js';
|
|
24
|
+
export { defaultBaseURLForProvider, defaultModelForProvider, GROQ_DEFAULT_BASE_URL, GROQ_DEFAULT_MODEL, groqAcceptedModel, isGroqCatalogModel, resolveInferenceRoute, resolveModelForProvider, } from './inference-route.js';
|
|
25
25
|
/**
|
|
26
26
|
* Providers reachable from a hosted (serverless) deployment. Localhost-only
|
|
27
27
|
* providers are false. Consumed by PR-2/PR-3 (resolver + settings UI) to pick
|
|
@@ -51,13 +51,20 @@ export class LLMClient {
|
|
|
51
51
|
rateLimitState;
|
|
52
52
|
responseCache;
|
|
53
53
|
semanticCache;
|
|
54
|
+
semanticCacheLoading;
|
|
54
55
|
healthMonitor;
|
|
55
56
|
circuitBreaker;
|
|
56
57
|
fallbackCircuitBreaker;
|
|
57
58
|
/** Tracks the last resolved API key so we only recreate the provider when it changes */
|
|
58
59
|
currentApiKey;
|
|
59
60
|
constructor(config) {
|
|
60
|
-
|
|
61
|
+
const route = resolveInferenceRoute({
|
|
62
|
+
provider: config.provider,
|
|
63
|
+
model: config.model,
|
|
64
|
+
baseURL: config.baseURL,
|
|
65
|
+
groqCredentialAvailable: config.provider === 'groq',
|
|
66
|
+
});
|
|
67
|
+
this.config = { ...config, ...route };
|
|
61
68
|
this.currentApiKey = config.apiKey;
|
|
62
69
|
this.rateLimitState = {
|
|
63
70
|
requests: [],
|
|
@@ -68,10 +75,10 @@ export class LLMClient {
|
|
|
68
75
|
if (config.enableResponseCache) {
|
|
69
76
|
this.responseCache = new ResponseCache(config.responseCacheOptions);
|
|
70
77
|
}
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
// SemanticCache is loaded on first chat() when enableSemanticCache is
|
|
79
|
+
// set. A static import pulls VectorMemoryService → @revealui/db/client →
|
|
80
|
+
// @revealui/config, which throws REVEALUI_PUBLIC_SERVER_URL in production
|
|
81
|
+
// (Apify Store 0.1.8). BYOK construction must not evaluate that graph.
|
|
75
82
|
// Wire health monitor if provided
|
|
76
83
|
this.healthMonitor = config.healthMonitor;
|
|
77
84
|
// Per-provider circuit breakers — isolate outages so one provider's failure
|
|
@@ -87,22 +94,22 @@ export class LLMClient {
|
|
|
87
94
|
}
|
|
88
95
|
// Wire dedicated embed provider if supplied
|
|
89
96
|
this.embedProviderOverride = config.embedProvider;
|
|
90
|
-
// Create primary provider
|
|
91
|
-
this.provider = this.createProvider(config.provider, {
|
|
92
|
-
apiKey: config.apiKey,
|
|
93
|
-
baseURL: config.baseURL,
|
|
94
|
-
model: config.model,
|
|
95
|
-
temperature: config.temperature,
|
|
96
|
-
maxTokens: config.maxTokens,
|
|
97
|
+
// Create primary provider from the resolved route (never a Groq id on OpenAI)
|
|
98
|
+
this.provider = this.createProvider(this.config.provider, {
|
|
99
|
+
apiKey: this.config.apiKey,
|
|
100
|
+
baseURL: this.config.baseURL,
|
|
101
|
+
model: this.config.model,
|
|
102
|
+
temperature: this.config.temperature,
|
|
103
|
+
maxTokens: this.config.maxTokens,
|
|
97
104
|
});
|
|
98
105
|
// Create fallback provider if specified
|
|
99
|
-
if (config.fallbackProvider) {
|
|
100
|
-
this.fallbackProvider = this.createProvider(config.fallbackProvider, {
|
|
101
|
-
apiKey: config.apiKey, // Note: In practice, you'd want separate API keys
|
|
102
|
-
baseURL: config.baseURL,
|
|
103
|
-
model: config.model,
|
|
104
|
-
temperature: config.temperature,
|
|
105
|
-
maxTokens: config.maxTokens,
|
|
106
|
+
if (this.config.fallbackProvider) {
|
|
107
|
+
this.fallbackProvider = this.createProvider(this.config.fallbackProvider, {
|
|
108
|
+
apiKey: this.config.apiKey, // Note: In practice, you'd want separate API keys
|
|
109
|
+
baseURL: this.config.baseURL,
|
|
110
|
+
model: this.config.model,
|
|
111
|
+
temperature: this.config.temperature,
|
|
112
|
+
maxTokens: this.config.maxTokens,
|
|
106
113
|
});
|
|
107
114
|
}
|
|
108
115
|
}
|
|
@@ -185,13 +192,29 @@ export class LLMClient {
|
|
|
185
192
|
this.rateLimitState.requests.push(now);
|
|
186
193
|
this.rateLimitState.dailyRequests++;
|
|
187
194
|
}
|
|
195
|
+
async ensureSemanticCache() {
|
|
196
|
+
if (!this.config.enableSemanticCache) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
if (this.semanticCache) {
|
|
200
|
+
return this.semanticCache;
|
|
201
|
+
}
|
|
202
|
+
if (!this.semanticCacheLoading) {
|
|
203
|
+
this.semanticCacheLoading = import('./semantic-cache.js').then(({ SemanticCache }) => {
|
|
204
|
+
this.semanticCache = new SemanticCache(this.config.semanticCacheOptions);
|
|
205
|
+
return this.semanticCache;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return this.semanticCacheLoading;
|
|
209
|
+
}
|
|
188
210
|
async chat(messages, options) {
|
|
189
211
|
await this.refreshProviderIfNeeded();
|
|
190
212
|
// Check semantic cache first (if enabled)
|
|
191
213
|
// Semantic cache is more powerful - matches similar queries, not just exact matches
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
214
|
+
const semanticCache = await this.ensureSemanticCache();
|
|
215
|
+
if (semanticCache) {
|
|
216
|
+
const query = semanticCache.extractQuery(messages);
|
|
217
|
+
const cached = await semanticCache.get(query);
|
|
195
218
|
if (cached) {
|
|
196
219
|
// Semantic cache hit - return immediately without API call
|
|
197
220
|
return {
|
|
@@ -241,9 +264,9 @@ export class LLMClient {
|
|
|
241
264
|
const response = await this.circuitBreaker.execute(() => this.provider.chat(messages, options));
|
|
242
265
|
this.healthMonitor?.recordCall(this.config.provider, Date.now() - callStart);
|
|
243
266
|
// Store in semantic cache (if enabled)
|
|
244
|
-
if (
|
|
245
|
-
const query =
|
|
246
|
-
await
|
|
267
|
+
if (semanticCache) {
|
|
268
|
+
const query = semanticCache.extractQuery(messages);
|
|
269
|
+
await semanticCache.set(query, response.content, response.usage);
|
|
247
270
|
}
|
|
248
271
|
// Store in response cache (if enabled)
|
|
249
272
|
if (this.responseCache) {
|
|
@@ -464,13 +487,13 @@ export class LLMClient {
|
|
|
464
487
|
*
|
|
465
488
|
* Canonical Inference Snaps is the reference local provider on Ubuntu — offline,
|
|
466
489
|
* silicon-optimized, no API key required. Product usage is **US-origin snaps
|
|
467
|
-
* only** (
|
|
490
|
+
* only** (gemma3 default; gemma4 and nemotron also allowlisted). See
|
|
468
491
|
* `providers/us-origin-snaps.ts` and `providers/inference-snaps.ts`.
|
|
469
492
|
*
|
|
470
493
|
* Provider defaults:
|
|
471
|
-
* inference-snaps →
|
|
472
|
-
* groq →
|
|
473
|
-
* ollama →
|
|
494
|
+
* inference-snaps → gemma3 (base URL defaults to http://localhost:9090/v1)
|
|
495
|
+
* groq → openai/gpt-oss-120b (Groq-accepted default; retired llama ids remap)
|
|
496
|
+
* ollama → DEFAULT_DAILY_OLLAMA_MODEL (qwen2.5:3b; base URL http://localhost:11434)
|
|
474
497
|
* anthropic → claude-sonnet-4-6 (base URL defaults to https://api.anthropic.com/v1)
|
|
475
498
|
* openai → gpt-4o (base URL defaults to https://api.openai.com/v1)
|
|
476
499
|
* xai → grok-4.5 (base URL defaults to https://api.x.ai/v1)
|
|
@@ -521,18 +544,18 @@ export function createLLMClientFromEnv() {
|
|
|
521
544
|
let defaultModel;
|
|
522
545
|
if (provider === 'anthropic') {
|
|
523
546
|
apiKey = process.env.ANTHROPIC_API_KEY;
|
|
524
|
-
baseURL = process.env.ANTHROPIC_BASE_URL ?? '
|
|
525
|
-
defaultModel = '
|
|
547
|
+
baseURL = process.env.ANTHROPIC_BASE_URL ?? defaultBaseURLForProvider('anthropic');
|
|
548
|
+
defaultModel = defaultModelForProvider('anthropic');
|
|
526
549
|
}
|
|
527
550
|
else if (provider === 'openai') {
|
|
528
551
|
apiKey = process.env.OPENAI_API_KEY;
|
|
529
|
-
baseURL = process.env.OPENAI_BASE_URL ?? '
|
|
530
|
-
defaultModel = '
|
|
552
|
+
baseURL = process.env.OPENAI_BASE_URL ?? defaultBaseURLForProvider('openai');
|
|
553
|
+
defaultModel = defaultModelForProvider('openai');
|
|
531
554
|
}
|
|
532
555
|
else if (provider === 'xai') {
|
|
533
556
|
apiKey = process.env.XAI_API_KEY;
|
|
534
|
-
baseURL = process.env.XAI_BASE_URL ?? '
|
|
535
|
-
defaultModel = '
|
|
557
|
+
baseURL = process.env.XAI_BASE_URL ?? defaultBaseURLForProvider('xai');
|
|
558
|
+
defaultModel = defaultModelForProvider('xai');
|
|
536
559
|
}
|
|
537
560
|
else if (provider === 'huggingface') {
|
|
538
561
|
apiKey = process.env.HF_TOKEN;
|
|
@@ -540,34 +563,43 @@ export function createLLMClientFromEnv() {
|
|
|
540
563
|
}
|
|
541
564
|
else if (provider === 'groq') {
|
|
542
565
|
apiKey = process.env.GROQ_API_KEY;
|
|
543
|
-
baseURL = process.env.GROQ_BASE_URL;
|
|
544
|
-
defaultModel = '
|
|
566
|
+
baseURL = process.env.GROQ_BASE_URL ?? defaultBaseURLForProvider('groq');
|
|
567
|
+
defaultModel = defaultModelForProvider('groq');
|
|
545
568
|
}
|
|
546
569
|
else if (provider === 'ollama') {
|
|
547
570
|
apiKey = 'ollama'; // Ollama ignores the API key
|
|
548
571
|
// Ollama's OpenAI-compatible endpoint lives at /v1
|
|
549
572
|
const ollamaBase = process.env.OLLAMA_BASE_URL ?? 'http://localhost:11434';
|
|
550
573
|
baseURL = ollamaBase.endsWith('/v1') ? ollamaBase : `${ollamaBase}/v1`;
|
|
551
|
-
defaultModel = '
|
|
574
|
+
defaultModel = defaultModelForProvider('ollama');
|
|
552
575
|
}
|
|
553
576
|
else if (provider === 'inference-snaps') {
|
|
554
577
|
apiKey = 'inference-snaps'; // inference-snaps ignores the API key
|
|
555
578
|
// Defaults to Canonical's Inference Snap local service on port 9090; override
|
|
556
579
|
// via INFERENCE_SNAPS_BASE_URL when the snap listens on a non-default port.
|
|
557
580
|
// Model defaults to the US-origin allowlist default (asserted in provider ctor).
|
|
558
|
-
baseURL = process.env.INFERENCE_SNAPS_BASE_URL ?? '
|
|
559
|
-
defaultModel =
|
|
581
|
+
baseURL = process.env.INFERENCE_SNAPS_BASE_URL ?? defaultBaseURLForProvider('inference-snaps');
|
|
582
|
+
defaultModel = defaultModelForProvider('inference-snaps');
|
|
583
|
+
}
|
|
584
|
+
const route = resolveInferenceRoute({
|
|
585
|
+
provider,
|
|
586
|
+
model: process.env.LLM_MODEL ?? defaultModel,
|
|
587
|
+
baseURL,
|
|
588
|
+
groqCredentialAvailable: Boolean(process.env.GROQ_API_KEY),
|
|
589
|
+
});
|
|
590
|
+
if (route.provider === 'groq' && provider !== 'groq') {
|
|
591
|
+
apiKey = process.env.GROQ_API_KEY;
|
|
560
592
|
}
|
|
561
593
|
if (!apiKey) {
|
|
562
|
-
throw new Error(`API key not found for provider "${provider}". Set the corresponding env var ` +
|
|
594
|
+
throw new Error(`API key not found for provider "${route.provider}". Set the corresponding env var ` +
|
|
563
595
|
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL, HF_TOKEN, ` +
|
|
564
596
|
`ANTHROPIC_API_KEY, OPENAI_API_KEY, or XAI_API_KEY).`);
|
|
565
597
|
}
|
|
566
598
|
return new LLMClient({
|
|
567
|
-
provider,
|
|
599
|
+
provider: route.provider,
|
|
568
600
|
apiKey,
|
|
569
|
-
baseURL,
|
|
570
|
-
model:
|
|
601
|
+
baseURL: route.baseURL,
|
|
602
|
+
model: route.model,
|
|
571
603
|
temperature: process.env.LLM_TEMPERATURE ? parseFloat(process.env.LLM_TEMPERATURE) : undefined,
|
|
572
604
|
maxTokens: process.env.LLM_MAX_TOKENS ? parseInt(process.env.LLM_MAX_TOKENS, 10) : undefined,
|
|
573
605
|
enableCacheByDefault: process.env.LLM_ENABLE_CACHE === 'true' || process.env.ANTHROPIC_ENABLE_CACHE === 'true',
|
|
@@ -580,9 +612,12 @@ export function createLLMClientFromEnv() {
|
|
|
580
612
|
/**
|
|
581
613
|
* Create an LLM client using a user's stored BYOK API key.
|
|
582
614
|
*
|
|
583
|
-
* Looks up the user's preferred provider from `tenant_provider_configs
|
|
584
|
-
*
|
|
585
|
-
*
|
|
615
|
+
* Looks up the user's preferred provider from `tenant_provider_configs`.
|
|
616
|
+
* If that provider has no saved key, uses another saved key (hosted-viable
|
|
617
|
+
* when `opts.hostedViableOnly` is set — e.g. a saved Groq key). Decrypts
|
|
618
|
+
* with AES-256-GCM and returns a configured LLMClient whose model and
|
|
619
|
+
* base URL match the **key's** provider, never a stale preferred-provider
|
|
620
|
+
* model (a Groq id must not be sent to OpenAI).
|
|
586
621
|
*
|
|
587
622
|
* Returns `null` if the user has no stored keys (callers should fall back
|
|
588
623
|
* to `createLLMClientFromEnv()` or return a 402/feature-unavailable error).
|
|
@@ -606,15 +641,22 @@ auditStore, opts) {
|
|
|
606
641
|
.from(tenantProviderConfigs)
|
|
607
642
|
.where(and(eq(tenantProviderConfigs.userId, userId), eq(tenantProviderConfigs.isDefault, true)))
|
|
608
643
|
.limit(1);
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
.
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
644
|
+
// All of this user's keys. Preferred provider wins when it has a key;
|
|
645
|
+
// otherwise use another saved key (hosted-viable on hosted).
|
|
646
|
+
const keyRows = await db.select().from(userApiKeys).where(eq(userApiKeys.userId, userId));
|
|
647
|
+
const preferredKey = preferredConfig
|
|
648
|
+
? keyRows.find((row) => row.provider === preferredConfig.provider)
|
|
649
|
+
: undefined;
|
|
650
|
+
const groqKey = keyRows.find((row) => row.provider === 'groq');
|
|
651
|
+
const fallbackKey = keyRows.find((row) => {
|
|
652
|
+
if (opts?.hostedViableOnly && !isHostedViable(row.provider)) {
|
|
653
|
+
return false;
|
|
654
|
+
}
|
|
655
|
+
return true;
|
|
656
|
+
});
|
|
657
|
+
const preferredModel = preferredConfig?.model ?? undefined;
|
|
658
|
+
const groqModelSelected = Boolean(preferredModel && isGroqCatalogModel(preferredModel));
|
|
659
|
+
const keyRow = groqModelSelected && groqKey ? groqKey : (preferredKey ?? fallbackKey);
|
|
618
660
|
if (!keyRow)
|
|
619
661
|
return null;
|
|
620
662
|
const provider = keyRow.provider;
|
|
@@ -623,7 +665,12 @@ auditStore, opts) {
|
|
|
623
665
|
if (opts?.hostedViableOnly && !isHostedViable(provider))
|
|
624
666
|
return null;
|
|
625
667
|
const plaintext = decryptApiKey(keyRow.encryptedKey);
|
|
626
|
-
const
|
|
668
|
+
const requestedModel = preferredConfig?.provider === provider || groqModelSelected ? preferredModel : undefined;
|
|
669
|
+
const route = resolveInferenceRoute({
|
|
670
|
+
provider,
|
|
671
|
+
model: requestedModel,
|
|
672
|
+
groqCredentialAvailable: provider === 'groq' || Boolean(groqKey),
|
|
673
|
+
});
|
|
627
674
|
// Fire-and-forget: record when this key was last used (best-effort, never blocks)
|
|
628
675
|
db.update(userApiKeys)
|
|
629
676
|
.set({ lastUsedAt: new Date() })
|
|
@@ -638,10 +685,15 @@ auditStore, opts) {
|
|
|
638
685
|
eventType: 'byok:key:accessed',
|
|
639
686
|
severity: 'info',
|
|
640
687
|
agentId: 'system',
|
|
641
|
-
payload: { userId, provider, keyId: keyRow.id },
|
|
688
|
+
payload: { userId, provider: route.provider, keyId: keyRow.id },
|
|
642
689
|
policyViolations: [],
|
|
643
690
|
})
|
|
644
691
|
.catch(() => undefined);
|
|
645
692
|
}
|
|
646
|
-
return new LLMClient({
|
|
693
|
+
return new LLMClient({
|
|
694
|
+
provider: route.provider,
|
|
695
|
+
apiKey: plaintext,
|
|
696
|
+
model: route.model,
|
|
697
|
+
baseURL: route.baseURL,
|
|
698
|
+
});
|
|
647
699
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider + model + host pairing for LLM clients.
|
|
3
|
+
*
|
|
4
|
+
* A2A Send Task and /api/agent-stream both construct an LLMClient through
|
|
5
|
+
* resolveLLMClientForRequest. This module is the single place that refuses
|
|
6
|
+
* the production pairing: a Groq catalog id on an OpenAI host
|
|
7
|
+
* (`llama-3.3-70b-versatile` posted to api.openai.com).
|
|
8
|
+
*/
|
|
9
|
+
export type LLMProviderType = 'anthropic' | 'openai' | 'groq' | 'huggingface' | 'ollama' | 'inference-snaps' | 'xai';
|
|
10
|
+
/** Groq's recommended replacement for llama-3.3-70b-versatile (retired 2026-08-16). */
|
|
11
|
+
export declare const GROQ_DEFAULT_MODEL = "openai/gpt-oss-120b";
|
|
12
|
+
export declare const GROQ_DEFAULT_BASE_URL = "https://api.groq.com/openai/v1";
|
|
13
|
+
export declare function isGroqCatalogModel(model: string): boolean;
|
|
14
|
+
/** Default catalog model for a provider. */
|
|
15
|
+
export declare function defaultModelForProvider(provider: LLMProviderType): string | undefined;
|
|
16
|
+
/** Default OpenAI-compatible base URL for a provider. */
|
|
17
|
+
export declare function defaultBaseURLForProvider(provider: LLMProviderType): string | undefined;
|
|
18
|
+
/** Current Groq-accepted model. Retired catalog ids map to the Groq default. */
|
|
19
|
+
export declare function groqAcceptedModel(requested: string | undefined): string;
|
|
20
|
+
/**
|
|
21
|
+
* Pick a model that belongs to `provider`. A Groq catalog id is never
|
|
22
|
+
* forwarded to OpenAI (walk residual: `llama-3.3-70b-versatile` on api.openai.com).
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveModelForProvider(provider: LLMProviderType, requested: string | undefined): string | undefined;
|
|
25
|
+
export interface InferenceRouteInput {
|
|
26
|
+
provider: LLMProviderType;
|
|
27
|
+
model?: string;
|
|
28
|
+
baseURL?: string;
|
|
29
|
+
/** True when a Groq credential is available (saved key or GROQ_API_KEY). */
|
|
30
|
+
groqCredentialAvailable?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface InferenceRoute {
|
|
33
|
+
provider: LLMProviderType;
|
|
34
|
+
model?: string;
|
|
35
|
+
baseURL?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolve provider, model, and host together.
|
|
39
|
+
*
|
|
40
|
+
* When the selected model is a Groq catalog id and a Groq credential exists,
|
|
41
|
+
* the request goes to Groq's OpenAI-compatible host with a Groq-accepted
|
|
42
|
+
* model. When the OpenAI client is actually used, a Groq id is replaced
|
|
43
|
+
* with the OpenAI default — never posted to api.openai.com.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveInferenceRoute(input: InferenceRouteInput): InferenceRoute;
|
|
46
|
+
//# sourceMappingURL=inference-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inference-route.d.ts","sourceRoot":"","sources":["../../src/llm/inference-route.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,QAAQ,GACR,MAAM,GACN,aAAa,GACb,QAAQ,GACR,iBAAiB,GACjB,KAAK,CAAC;AAEV,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,wBAAwB,CAAC;AACxD,eAAO,MAAM,qBAAqB,mCAAmC,CAAC;AAyCtE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASzD;AAED,4CAA4C;AAC5C,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAiBrF;AAED,yDAAyD;AACzD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAiBvF;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKvE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,SAAS,CAQpB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiBD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAkBhF"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider + model + host pairing for LLM clients.
|
|
3
|
+
*
|
|
4
|
+
* A2A Send Task and /api/agent-stream both construct an LLMClient through
|
|
5
|
+
* resolveLLMClientForRequest. This module is the single place that refuses
|
|
6
|
+
* the production pairing: a Groq catalog id on an OpenAI host
|
|
7
|
+
* (`llama-3.3-70b-versatile` posted to api.openai.com).
|
|
8
|
+
*/
|
|
9
|
+
import { DEFAULT_DAILY_OLLAMA_MODEL, DEFAULT_US_ORIGIN_INFERENCE_SNAP, } from './providers/us-origin-snaps.js';
|
|
10
|
+
/** Groq's recommended replacement for llama-3.3-70b-versatile (retired 2026-08-16). */
|
|
11
|
+
export const GROQ_DEFAULT_MODEL = 'openai/gpt-oss-120b';
|
|
12
|
+
export const GROQ_DEFAULT_BASE_URL = 'https://api.groq.com/openai/v1';
|
|
13
|
+
/**
|
|
14
|
+
* Groq catalog ids — current and retired — that must never be sent to
|
|
15
|
+
* api.openai.com. Set lookup plus prefix checks; no regex (M2).
|
|
16
|
+
*/
|
|
17
|
+
const GROQ_CATALOG_MODELS = new Set([
|
|
18
|
+
'llama-3.3-70b-versatile',
|
|
19
|
+
'llama-3.3-70b-specdec',
|
|
20
|
+
'llama-3.1-70b-versatile',
|
|
21
|
+
'llama-3.1-8b-instant',
|
|
22
|
+
'llama-3.2-90b-vision-preview',
|
|
23
|
+
'llama-3.2-11b-vision-preview',
|
|
24
|
+
'llama-3.2-3b-preview',
|
|
25
|
+
'llama-3.2-1b-preview',
|
|
26
|
+
'mixtral-8x7b-32768',
|
|
27
|
+
'gemma2-9b-it',
|
|
28
|
+
'gemma-7b-it',
|
|
29
|
+
'qwen/qwen3-32b',
|
|
30
|
+
'qwen/qwen3.6-27b',
|
|
31
|
+
'openai/gpt-oss-120b',
|
|
32
|
+
'openai/gpt-oss-20b',
|
|
33
|
+
'openai/gpt-oss-safeguard-20b',
|
|
34
|
+
]);
|
|
35
|
+
/** Retired Groq ids that the public API rejects (same error text as OpenAI). */
|
|
36
|
+
const GROQ_RETIRED_MODELS = new Set([
|
|
37
|
+
'llama-3.3-70b-versatile',
|
|
38
|
+
'llama-3.3-70b-specdec',
|
|
39
|
+
'llama-3.1-70b-versatile',
|
|
40
|
+
'llama-3.1-8b-instant',
|
|
41
|
+
'llama-3.2-90b-vision-preview',
|
|
42
|
+
'llama-3.2-11b-vision-preview',
|
|
43
|
+
'llama-3.2-3b-preview',
|
|
44
|
+
'llama-3.2-1b-preview',
|
|
45
|
+
'mixtral-8x7b-32768',
|
|
46
|
+
'gemma2-9b-it',
|
|
47
|
+
'gemma-7b-it',
|
|
48
|
+
'qwen/qwen3-32b',
|
|
49
|
+
]);
|
|
50
|
+
export function isGroqCatalogModel(model) {
|
|
51
|
+
if (GROQ_CATALOG_MODELS.has(model))
|
|
52
|
+
return true;
|
|
53
|
+
return (model.startsWith('llama-3.') ||
|
|
54
|
+
model.startsWith('mixtral-') ||
|
|
55
|
+
model.startsWith('gemma2-') ||
|
|
56
|
+
model.startsWith('openai/gpt-oss') ||
|
|
57
|
+
model.startsWith('qwen/qwen3'));
|
|
58
|
+
}
|
|
59
|
+
/** Default catalog model for a provider. */
|
|
60
|
+
export function defaultModelForProvider(provider) {
|
|
61
|
+
switch (provider) {
|
|
62
|
+
case 'anthropic':
|
|
63
|
+
return 'claude-sonnet-4-6';
|
|
64
|
+
case 'openai':
|
|
65
|
+
return 'gpt-4o';
|
|
66
|
+
case 'xai':
|
|
67
|
+
return 'grok-4.5';
|
|
68
|
+
case 'groq':
|
|
69
|
+
return GROQ_DEFAULT_MODEL;
|
|
70
|
+
case 'ollama':
|
|
71
|
+
return DEFAULT_DAILY_OLLAMA_MODEL;
|
|
72
|
+
case 'inference-snaps':
|
|
73
|
+
return DEFAULT_US_ORIGIN_INFERENCE_SNAP;
|
|
74
|
+
default:
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Default OpenAI-compatible base URL for a provider. */
|
|
79
|
+
export function defaultBaseURLForProvider(provider) {
|
|
80
|
+
switch (provider) {
|
|
81
|
+
case 'anthropic':
|
|
82
|
+
return 'https://api.anthropic.com/v1';
|
|
83
|
+
case 'openai':
|
|
84
|
+
return 'https://api.openai.com/v1';
|
|
85
|
+
case 'xai':
|
|
86
|
+
return 'https://api.x.ai/v1';
|
|
87
|
+
case 'groq':
|
|
88
|
+
return GROQ_DEFAULT_BASE_URL;
|
|
89
|
+
case 'ollama':
|
|
90
|
+
return 'http://localhost:11434/v1';
|
|
91
|
+
case 'inference-snaps':
|
|
92
|
+
return 'http://localhost:9090/v1';
|
|
93
|
+
default:
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Current Groq-accepted model. Retired catalog ids map to the Groq default. */
|
|
98
|
+
export function groqAcceptedModel(requested) {
|
|
99
|
+
if (requested && isGroqCatalogModel(requested) && !GROQ_RETIRED_MODELS.has(requested)) {
|
|
100
|
+
return requested;
|
|
101
|
+
}
|
|
102
|
+
return GROQ_DEFAULT_MODEL;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Pick a model that belongs to `provider`. A Groq catalog id is never
|
|
106
|
+
* forwarded to OpenAI (walk residual: `llama-3.3-70b-versatile` on api.openai.com).
|
|
107
|
+
*/
|
|
108
|
+
export function resolveModelForProvider(provider, requested) {
|
|
109
|
+
if (provider === 'groq') {
|
|
110
|
+
return groqAcceptedModel(requested);
|
|
111
|
+
}
|
|
112
|
+
if (requested && !isGroqCatalogModel(requested)) {
|
|
113
|
+
return requested;
|
|
114
|
+
}
|
|
115
|
+
return defaultModelForProvider(provider);
|
|
116
|
+
}
|
|
117
|
+
const OPENAI_API_HOSTNAME = 'api.openai.com';
|
|
118
|
+
/**
|
|
119
|
+
* True only when `url` is a parseable absolute URL whose hostname is exactly
|
|
120
|
+
* api.openai.com. Prefix/substring checks are not used — `api.openai.com.evil.com`
|
|
121
|
+
* must not count as OpenAI (CodeQL js/incomplete-url-substring-sanitization).
|
|
122
|
+
*/
|
|
123
|
+
function isOpenAiHost(url) {
|
|
124
|
+
try {
|
|
125
|
+
return new URL(url).hostname === OPENAI_API_HOSTNAME;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolve provider, model, and host together.
|
|
133
|
+
*
|
|
134
|
+
* When the selected model is a Groq catalog id and a Groq credential exists,
|
|
135
|
+
* the request goes to Groq's OpenAI-compatible host with a Groq-accepted
|
|
136
|
+
* model. When the OpenAI client is actually used, a Groq id is replaced
|
|
137
|
+
* with the OpenAI default — never posted to api.openai.com.
|
|
138
|
+
*/
|
|
139
|
+
export function resolveInferenceRoute(input) {
|
|
140
|
+
const groqModel = Boolean(input.model && isGroqCatalogModel(input.model));
|
|
141
|
+
if (groqModel && (input.provider === 'groq' || input.groqCredentialAvailable)) {
|
|
142
|
+
const keepCustomGroqUrl = Boolean(input.provider === 'groq' && input.baseURL && !isOpenAiHost(input.baseURL));
|
|
143
|
+
return {
|
|
144
|
+
provider: 'groq',
|
|
145
|
+
model: groqAcceptedModel(input.model),
|
|
146
|
+
baseURL: keepCustomGroqUrl ? input.baseURL : defaultBaseURLForProvider('groq'),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
provider: input.provider,
|
|
151
|
+
model: resolveModelForProvider(input.provider, input.model),
|
|
152
|
+
baseURL: input.baseURL ?? defaultBaseURLForProvider(input.provider),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-ai-profile.d.ts","sourceRoot":"","sources":["../../src/llm/local-ai-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"local-ai-profile.d.ts","sourceRoot":"","sources":["../../src/llm/local-ai-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/D,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,iBAAiB,GAAG,IAAI,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0CAA0C;IAC1C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,8DAA8D;IAC9D,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAK9C;AAED,gEAAgE;AAChE,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,IAAI,cAAc,CAiBjD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAgC,GAAG,cAAc,GAAG,IAAI,CAShG;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,MAAgC,GACrC,IAAI,CAqCN;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,cAAc,GAAG,IAA2B,GACpD,IAAI,CAyBN;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,GAChB,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC,CAuC/E"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { homedir } from 'node:os';
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
|
-
import { DEFAULT_DAILY_OLLAMA_MODEL, DEFAULT_LOW_RAM_INFERENCE_SNAP,
|
|
13
|
+
import { DEFAULT_DAILY_OLLAMA_MODEL, DEFAULT_LOW_RAM_INFERENCE_SNAP, } from './providers/us-origin-snaps.js';
|
|
14
14
|
export function getLocalAiProfilePath() {
|
|
15
15
|
return (process.env.REVEALUI_INFERENCE_PROFILE_PATH ??
|
|
16
16
|
join(homedir(), '.local', 'share', 'revealui', 'inference-profile.json'));
|
|
@@ -139,7 +139,7 @@ export function profileDefaultsForTier(tier) {
|
|
|
139
139
|
model: DEFAULT_DAILY_OLLAMA_MODEL,
|
|
140
140
|
baseURL: 'http://127.0.0.1:11434',
|
|
141
141
|
keepAlive: '0',
|
|
142
|
-
note: 'Ollama
|
|
142
|
+
note: 'Ollama daily default (qwen2.5:3b); weights unload after each request',
|
|
143
143
|
};
|
|
144
144
|
case 'snaps':
|
|
145
145
|
return {
|
|
@@ -152,7 +152,7 @@ export function profileDefaultsForTier(tier) {
|
|
|
152
152
|
case 'heavy':
|
|
153
153
|
return {
|
|
154
154
|
provider: 'inference-snaps',
|
|
155
|
-
model:
|
|
155
|
+
model: 'nemotron-3-nano',
|
|
156
156
|
baseURL: null,
|
|
157
157
|
keepAlive: null,
|
|
158
158
|
note: 'Heavy snap — needs substantial RAM; avoid concurrent IDE load on 4GB WSL',
|
|
@@ -10,7 +10,7 @@ export interface GroqProviderConfig extends Omit<LLMProviderConfig, 'apiKey'> {
|
|
|
10
10
|
apiKey: string;
|
|
11
11
|
/** Defaults to https://api.groq.com/openai/v1 */
|
|
12
12
|
baseURL?: string;
|
|
13
|
-
/** Defaults to
|
|
13
|
+
/** Defaults to openai/gpt-oss-120b (current Groq-accepted catalog) */
|
|
14
14
|
model?: string;
|
|
15
15
|
}
|
|
16
16
|
export declare class GroqProvider implements LLMProvider {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groq.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/groq.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"groq.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/groq.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,OAAO,EACP,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAGnB,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAa,YAAW,WAAW;IAC9C,OAAO,CAAC,KAAK,CAAuB;gBAExB,MAAM,EAAE,kBAAkB;IAUtC,YAAY,IAAI,oBAAoB;IAepC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAAC;IAIhF,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;CAG9F"}
|
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
* Free tier: 6,000 TPM / 500k TPD.
|
|
6
6
|
* Sign up: console.groq.com
|
|
7
7
|
*/
|
|
8
|
+
import { GROQ_DEFAULT_BASE_URL, GROQ_DEFAULT_MODEL } from '../inference-route.js';
|
|
8
9
|
import { OpenAICompatProvider } from './openai-compat.js';
|
|
9
10
|
export class GroqProvider {
|
|
10
11
|
inner;
|
|
11
12
|
constructor(config) {
|
|
12
13
|
this.inner = new OpenAICompatProvider({
|
|
13
14
|
...config,
|
|
14
|
-
baseURL: config.baseURL ??
|
|
15
|
-
|
|
15
|
+
baseURL: config.baseURL ?? GROQ_DEFAULT_BASE_URL,
|
|
16
|
+
// Retired catalog ids (llama-3.3-70b-versatile, qwen/qwen3-32b) 404 on
|
|
17
|
+
// Groq's public API as of 2026-08-16. Prefer the current Groq default.
|
|
18
|
+
model: config.model ?? GROQ_DEFAULT_MODEL,
|
|
16
19
|
});
|
|
17
20
|
}
|
|
18
21
|
capabilities() {
|
|
19
|
-
// Profile for the default model
|
|
22
|
+
// Profile for the default model. Groq exposes no embeddings endpoint.
|
|
20
23
|
return {
|
|
21
24
|
providerTag: 'groq',
|
|
22
25
|
tools: true,
|
|
@@ -6,17 +6,18 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Product hardline: US-origin snap models only (see us-origin-snaps.ts).
|
|
8
8
|
* Allowlisted snaps (install these):
|
|
9
|
-
*
|
|
9
|
+
* gemma3 - Google general + vision (default; WSL-supported)
|
|
10
|
+
* gemma4 - Google general + vision + tools
|
|
11
|
+
* nemotron-3-nano - NVIDIA general + tools (heavy / capable hosts)
|
|
10
12
|
* nemotron-3-nano-omni - NVIDIA multimodal
|
|
11
|
-
* gemma3 / gemma4 - Google general + vision + tools
|
|
12
13
|
*
|
|
13
14
|
* Canonical also publishes non-US snaps (deepseek-r1, qwen-*, glm-*). Those
|
|
14
15
|
* are rejected at construction unless REVEALUI_ALLOW_NON_US_MODELS=1.
|
|
15
16
|
*
|
|
16
17
|
* Install a model:
|
|
17
|
-
* sudo snap install
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* sudo snap install gemma3
|
|
19
|
+
* gemma3 set http.port=9090 --assume-yes
|
|
20
|
+
* gemma3 status # shows base URL and available models
|
|
20
21
|
*
|
|
21
22
|
* Set env vars:
|
|
22
23
|
* INFERENCE_SNAPS_BASE_URL=http://localhost:9090/v1
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,OAAO,EACP,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAEL,gCAAgC,EACjC,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,qBAAa,sBAAuB,YAAW,WAAW;IACxD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,4BAA4B;IAchD,YAAY,IAAI,oBAAoB;IAgBpC,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;AAED,OAAO,EAAE,gCAAgC,EAAE,CAAC"}
|