From 0571313a4ac06255853fff83e2e6a3c8c5d7cbf9 Mon Sep 17 00:00:00 2001 From: pipper Date: Tue, 9 Sep 2025 18:08:52 +0200 Subject: [PATCH 01/12] initial endpoint --- .../src/app/plugins/remixAIPlugin.tsx | 6 ++- .../src/app/tabs/locales/en/settings.json | 5 ++- libs/remix-ai-core/src/index.ts | 4 +- .../src/inferencers/local/ollama.ts | 39 +++++++++++++++++++ .../settings/src/lib/remix-ui-settings.tsx | 10 +++++ .../settings/src/lib/settingsReducer.ts | 27 +++++++++++++ libs/remix-ui/settings/src/types/index.ts | 2 + 7 files changed, 89 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index 6503110da8c..b333ca40818 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -1,6 +1,6 @@ import * as packageJson from '../../../../../package.json' import { Plugin } from '@remixproject/engine'; -import { IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, AssistantParams, CodeExplainAgent, SecurityAgent, CompletionParams, OllamaInferencer, isOllamaAvailable, getBestAvailableModel } from '@remix/remix-ai-core'; +import { IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, AssistantParams, CodeExplainAgent, SecurityAgent, CompletionParams, OllamaInferencer, isOllamaAvailable, getBestAvailableModel, resetOllamaHostOnSettingsChange } from '@remix/remix-ai-core'; import { CodeCompletionAgent, ContractAgent, workspaceAgent, IContextType } from '@remix/remix-ai-core'; import axios from 'axios'; import { endpointUrls } from "@remix-endpoints-helper" @@ -53,6 +53,10 @@ export class RemixAIPlugin extends Plugin { } onActivation(): void { + // Expose Ollama reset function globally for settings integration + if (typeof window !== 'undefined') { + (window as any).resetOllamaHostOnSettingsChange = resetOllamaHostOnSettingsChange; + } if (this.isOnDesktop) { this.useRemoteInferencer = true diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index 85223986235..0f930d99181 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -65,5 +65,8 @@ "settings.aiCopilotDescription": "AI Copilot assists with code suggestions and improvements.", "settings.aiPrivacyPolicy": "AI Privacy & Data Usage", "settings.viewPrivacyPolicy": "View Privacy Policy", - "settings.aiPrivacyPolicyDescription": "Understand how AI processes your data." + "settings.aiPrivacyPolicyDescription": "Understand how AI processes your data.", + "settings.ollamaConfig": "Ollama Configuration", + "settings.ollamaConfigDescription": "Configure Ollama endpoint for local AI model integration", + "settings.ollama-endpoint": "ENDPOINT URL" } diff --git a/libs/remix-ai-core/src/index.ts b/libs/remix-ai-core/src/index.ts index 1a8a9693bdd..60401239a26 100644 --- a/libs/remix-ai-core/src/index.ts +++ b/libs/remix-ai-core/src/index.ts @@ -7,7 +7,7 @@ import { DefaultModels, InsertionParams, CompletionParams, GenerationParams, Ass import { buildChatPrompt } from './prompts/promptBuilder' import { RemoteInferencer } from './inferencers/remote/remoteInference' import { OllamaInferencer } from './inferencers/local/ollamaInferencer' -import { isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost } from './inferencers/local/ollama' +import { isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, resetOllamaHostOnSettingsChange } from './inferencers/local/ollama' import { FIMModelManager, FIMModelConfig, FIM_MODEL_CONFIGS } from './inferencers/local/fimModelConfig' import { ChatHistory } from './prompts/chat' import { downloadLatestReleaseExecutable } from './helpers/inferenceServerReleases' @@ -15,7 +15,7 @@ import { ChatCommandParser } from './helpers/chatCommandParser' export { IModel, IModelResponse, ChatCommandParser, ModelType, DefaultModels, ICompletions, IParams, IRemoteModel, buildChatPrompt, - RemoteInferencer, OllamaInferencer, isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, + RemoteInferencer, OllamaInferencer, isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, resetOllamaHostOnSettingsChange, FIMModelManager, FIMModelConfig, FIM_MODEL_CONFIGS, InsertionParams, CompletionParams, GenerationParams, AssistantParams, ChatEntry, AIRequestType, ChatHistory, downloadLatestReleaseExecutable diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 605197ddef3..8075e855797 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -1,19 +1,52 @@ import axios from 'axios'; +import { Registry } from '@remix-project/remix-lib'; const _paq = (typeof window !== 'undefined' && (window as any)._paq) ? (window as any)._paq : [] // default Ollama ports to check (11434 is the legacy/standard port) const OLLAMA_PORTS = [11434, 11435, 11436]; const OLLAMA_BASE_HOST = 'http://localhost'; +const DEFAULT_OLLAMA_HOST = 'http://localhost:11434'; let discoveredOllamaHost: string | null = null; +function getConfiguredOllamaEndpoint(): string | null { + try { + const config = Registry.getInstance().get('config').api; + const configuredEndpoint = config.get('settings/ollama-endpoint'); + if (configuredEndpoint && configuredEndpoint !== DEFAULT_OLLAMA_HOST) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_using_configured_endpoint', configuredEndpoint]); + return configuredEndpoint; + } + } catch (error) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_config_access_failed', error.message || 'unknown']); + } + return null; +} + export async function discoverOllamaHost(): Promise { if (discoveredOllamaHost) { _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_host_cache_hit', discoveredOllamaHost]); return discoveredOllamaHost; } + // First, try to use the configured endpoint from settings + const configuredEndpoint = getConfiguredOllamaEndpoint(); + if (configuredEndpoint) { + try { + const res = await axios.get(`${configuredEndpoint}/api/tags`, { timeout: 2000 }); + if (res.status === 200) { + discoveredOllamaHost = configuredEndpoint; + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_success', configuredEndpoint]); + return configuredEndpoint; + } + } catch (error) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_failed', `${configuredEndpoint}:${error.message || 'unknown'}`]); + // Fall back to discovery if configured endpoint fails + } + } + + // Fall back to port discovery if no configured endpoint or it failed for (const port of OLLAMA_PORTS) { const host = `${OLLAMA_BASE_HOST}:${port}`; _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_port_check', `${port}`]); @@ -66,6 +99,12 @@ export function resetOllamaHost(): void { discoveredOllamaHost = null; } +export function resetOllamaHostOnSettingsChange(): void { + // This function should be called when Ollama settings are updated + resetOllamaHost(); + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_reset_on_settings_change']); +} + export async function pullModel(modelName: string): Promise { // in case the user wants to pull a model from registry _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_pull_model_start', modelName]); diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index 409c7a9dcc7..80206235bf2 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -139,6 +139,16 @@ const settingsSections: SettingsSection[] = [ action: 'link', link: 'https://remix-ide.readthedocs.io/en/latest/ai.html' } + }, + { + name: 'ollama-config', + label: 'settings.ollamaConfig', + description: 'settings.ollamaConfigDescription', + type: 'toggle', + toggleUIOptions: [{ + name: 'ollama-endpoint', + type: 'text' + }] }] } ]}, diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index c4b703f03e8..1825c47eace 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -17,12 +17,14 @@ const swarmPrivateBeeAddress = config.get('settings/swarm-private-bee-address') const swarmPostageStampId = config.get('settings/swarm-postage-stamp-id') || '' const sindriAccessToken = config.get('settings/sindri-access-token') || '' const etherscanAccessToken = config.get('settings/etherscan-access-token') || '' +const ollamaEndpoint = config.get('settings/ollama-endpoint') || 'http://localhost:11434' let githubConfig = config.get('settings/github-config') || false let ipfsConfig = config.get('settings/ipfs-config') || false let swarmConfig = config.get('settings/swarm-config') || false let sindriConfig = config.get('settings/sindri-config') || false let etherscanConfig = config.get('settings/etherscan-config') || false +let ollamaConfig = config.get('settings/ollama-config') || false let generateContractMetadata = config.get('settings/generate-contract-metadata') let autoCompletion = config.get('settings/auto-completion') let showGas = config.get('settings/show-gas') @@ -49,6 +51,10 @@ if (!etherscanConfig && etherscanAccessToken) { config.set('settings/etherscan-config', true) etherscanConfig = true } +if (!ollamaConfig && ollamaEndpoint !== 'http://localhost:11434') { + config.set('settings/ollama-config', true) + ollamaConfig = true +} if (typeof generateContractMetadata !== 'boolean') { config.set('settings/generate-contract-metadata', true) generateContractMetadata = true @@ -191,6 +197,14 @@ export const initialState: SettingsState = { value: '', isLoading: false }, + 'ollama-config': { + value: ollamaConfig, + isLoading: false + }, + 'ollama-endpoint': { + value: ollamaEndpoint, + isLoading: false + }, toaster: { value: '', isLoading: false @@ -201,6 +215,19 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S switch (action.type) { case 'SET_VALUE': config.set('settings/' + action.payload.name, action.payload.value) + + // Reset Ollama host cache when endpoint is changed + if (action.payload.name === 'ollama-endpoint') { + try { + // Check if the resetOllamaHostOnSettingsChange function is available globally + if (typeof window !== 'undefined' && (window as any).resetOllamaHostOnSettingsChange) { + (window as any).resetOllamaHostOnSettingsChange(); + } + } catch (error) { + // Ignore errors - Ollama functionality is optional + } + } + return { ...state, [action.payload.name]: { ...state[action.payload.name], value: action.payload.value, isLoading: false } } case 'SET_LOADING': return { ...state, [action.payload.name]: { ...state[action.payload.name], isLoading: true } } diff --git a/libs/remix-ui/settings/src/types/index.ts b/libs/remix-ui/settings/src/types/index.ts index 03e938aab22..c974e8dea61 100644 --- a/libs/remix-ui/settings/src/types/index.ts +++ b/libs/remix-ui/settings/src/types/index.ts @@ -112,6 +112,8 @@ export interface SettingsState { 'sindri-access-token': ConfigState, 'etherscan-access-token': ConfigState, 'ai-privacy-policy': ConfigState, + 'ollama-config': ConfigState, + 'ollama-endpoint': ConfigState, toaster: ConfigState } export interface SettingsActionPayloadTypes { From 63e67d0b4ffb8ca49ebf94519177f80fc838fd25 Mon Sep 17 00:00:00 2001 From: pipper Date: Wed, 10 Sep 2025 09:13:27 +0200 Subject: [PATCH 02/12] working on remote URL --- apps/remix-ide/src/app/plugins/remixAIPlugin.tsx | 1 - apps/remix-ide/src/app/tabs/locales/en/settings.json | 2 +- libs/remix-ai-core/src/inferencers/local/ollama.ts | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index b333ca40818..6490859916c 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -423,7 +423,6 @@ export class RemixAIPlugin extends Plugin { this.isInferencing = false }) - console.log(`Ollama model changed to: ${modelName}`) } catch (error) { console.error('Failed to set Ollama model:', error) } diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index 0f930d99181..52c898fbcf3 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -66,7 +66,7 @@ "settings.aiPrivacyPolicy": "AI Privacy & Data Usage", "settings.viewPrivacyPolicy": "View Privacy Policy", "settings.aiPrivacyPolicyDescription": "Understand how AI processes your data.", - "settings.ollamaConfig": "Ollama Configuration", + "settings.ollamaConfig": "Ollama URL Configuration", "settings.ollamaConfigDescription": "Configure Ollama endpoint for local AI model integration", "settings.ollama-endpoint": "ENDPOINT URL" } diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 8075e855797..db9b62dc0f9 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -40,13 +40,15 @@ export async function discoverOllamaHost(): Promise { _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_success', configuredEndpoint]); return configuredEndpoint; } + return null; } catch (error) { _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_failed', `${configuredEndpoint}:${error.message || 'unknown'}`]); // Fall back to discovery if configured endpoint fails + return null; } } - // Fall back to port discovery if no configured endpoint or it failed + // Fall back to port discovery if no configured endpoint for (const port of OLLAMA_PORTS) { const host = `${OLLAMA_BASE_HOST}:${port}`; _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_port_check', `${port}`]); From eee9a127fb95d525b08d942cc0c9002ecd1964c5 Mon Sep 17 00:00:00 2001 From: pipper Date: Thu, 11 Sep 2025 09:35:48 +0200 Subject: [PATCH 03/12] rm global function --- .gitignore | 3 ++- apps/remix-ide/src/app/plugins/remixAIPlugin.tsx | 4 +--- libs/remix-ui/settings/src/lib/settingsReducer.ts | 7 ++----- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 6599f59e045..2cfd04832e6 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,5 @@ apps/remixdesktop/circom-download apps/remixdesktop/log_input_signals.txt apps/remixdesktop/log_input_signals_new.txt logs -apps/remix-ide-e2e/src/extensions/chrome/metamask \ No newline at end of file +apps/remix-ide-e2e/src/extensions/chrome/metamask +apps/remix-ide-e2e/tmp/ \ No newline at end of file diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index 6490859916c..3323fe3b003 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -54,9 +54,7 @@ export class RemixAIPlugin extends Plugin { onActivation(): void { // Expose Ollama reset function globally for settings integration - if (typeof window !== 'undefined') { - (window as any).resetOllamaHostOnSettingsChange = resetOllamaHostOnSettingsChange; - } + resetOllamaHostOnSettingsChange(); if (this.isOnDesktop) { this.useRemoteInferencer = true diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 1825c47eace..2c956f7d7b7 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -1,6 +1,6 @@ import { Registry } from '@remix-project/remix-lib' import { SettingsActions, SettingsState } from '../types' - +import { resetOllamaHostOnSettingsChange } from '@remix/remix-ai-core'; const config = Registry.getInstance().get('config').api const settingsConfig = Registry.getInstance().get('settingsConfig').api const defaultTheme = config.get('settings/theme') ? settingsConfig.themes.find((theme) => theme.name.toLowerCase() === config.get('settings/theme').toLowerCase()) : settingsConfig.themes[0] @@ -219,10 +219,7 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S // Reset Ollama host cache when endpoint is changed if (action.payload.name === 'ollama-endpoint') { try { - // Check if the resetOllamaHostOnSettingsChange function is available globally - if (typeof window !== 'undefined' && (window as any).resetOllamaHostOnSettingsChange) { - (window as any).resetOllamaHostOnSettingsChange(); - } + resetOllamaHostOnSettingsChange(); } catch (error) { // Ignore errors - Ollama functionality is optional } From 5e821be200f82efea4bc001a602ec8dec5dc979b Mon Sep 17 00:00:00 2001 From: pipper Date: Mon, 13 Oct 2025 18:22:03 +0200 Subject: [PATCH 04/12] minor --- apps/remix-ide/src/app/tabs/locales/en/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index e9e9c31233a..317a332ce7c 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -67,6 +67,6 @@ "settings.viewPrivacyPolicy": "View Privacy Policy", "settings.ollamaConfig": "Ollama URL Configuration", "settings.ollamaConfigDescription": "Configure Ollama endpoint for local AI model integration", - "settings.ollama-endpoint": "ENDPOINT URL" + "settings.ollama-endpoint": "ENDPOINT URL", "settings.aiPrivacyPolicyDescription": "Understand how RemixAI processes your data." } From e37142bf5673161fdd616acd82a5cb635adf5924 Mon Sep 17 00:00:00 2001 From: pipper Date: Mon, 13 Oct 2025 19:19:44 +0200 Subject: [PATCH 05/12] linting --- libs/remix-ui/settings/src/lib/settingsReducer.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 2a451c1ca57..a9a202a81a9 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -210,7 +210,6 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S switch (action.type) { case 'SET_VALUE': config.set('settings/' + action.payload.name, action.payload.value) - // Reset Ollama host cache when endpoint is changed if (action.payload.name === 'ollama-endpoint') { try { @@ -219,7 +218,7 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S // Ignore errors - Ollama functionality is optional } } - + return { ...state, [action.payload.name]: { ...state[action.payload.name], value: action.payload.value, isLoading: false } } case 'SET_LOADING': return { ...state, [action.payload.name]: { ...state[action.payload.name], isLoading: true } } From cc56462d0fbb94ffbd1b8f9e240cf82c0047ded2 Mon Sep 17 00:00:00 2001 From: pipper Date: Tue, 9 Sep 2025 18:08:52 +0200 Subject: [PATCH 06/12] initial endpoint --- .../src/app/plugins/remixAIPlugin.tsx | 6 ++- .../src/app/tabs/locales/en/settings.json | 5 ++- libs/remix-ai-core/src/index.ts | 4 +- .../src/inferencers/local/ollama.ts | 39 +++++++++++++++++++ .../settings/src/lib/remix-ui-settings.tsx | 10 +++++ .../settings/src/lib/settingsReducer.ts | 28 +++++++++++++ libs/remix-ui/settings/src/types/index.ts | 2 + 7 files changed, 90 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index c4b1e67f5f0..43f7cefc05d 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -1,7 +1,7 @@ import * as packageJson from '../../../../../package.json' import { Plugin } from '@remixproject/engine'; import { trackMatomoEvent } from '@remix-api' -import { IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, AssistantParams, CodeExplainAgent, SecurityAgent, CompletionParams, OllamaInferencer, isOllamaAvailable, getBestAvailableModel } from '@remix/remix-ai-core'; +import { IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, AssistantParams, CodeExplainAgent, SecurityAgent, CompletionParams, OllamaInferencer, isOllamaAvailable, getBestAvailableModel, resetOllamaHostOnSettingsChange } from '@remix/remix-ai-core'; import { CodeCompletionAgent, ContractAgent, workspaceAgent, IContextType, mcpDefaultServersConfig } from '@remix/remix-ai-core'; import { MCPInferencer } from '@remix/remix-ai-core'; import { IMCPServer, IMCPConnectionStatus } from '@remix/remix-ai-core'; @@ -63,6 +63,10 @@ export class RemixAIPlugin extends Plugin { } onActivation(): void { + // Expose Ollama reset function globally for settings integration + if (typeof window !== 'undefined') { + (window as any).resetOllamaHostOnSettingsChange = resetOllamaHostOnSettingsChange; + } if (this.isOnDesktop) { this.useRemoteInferencer = true diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index 5ac3129d765..3900d1a7d0a 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -69,5 +69,8 @@ "settings.mcpServerConfigurationDescription": "Connect to Model Context Protocol servers for enhanced AI context", "settings.enableMCPEnhancement": "Enable MCP Integration", "settings.enableMCPEnhancementDescription": "Manage your MCP server connections", - "settings.aiPrivacyPolicyDescription": "Understand how RemixAI processes your data." + "settings.aiPrivacyPolicyDescription": "Understand how RemixAI processes your data.", + "settings.ollamaConfig": "Ollama Configuration", + "settings.ollamaConfigDescription": "Configure Ollama endpoint for local AI model integration", + "settings.ollama-endpoint": "ENDPOINT URL" } diff --git a/libs/remix-ai-core/src/index.ts b/libs/remix-ai-core/src/index.ts index 62ca148ef0a..ba298f68728 100644 --- a/libs/remix-ai-core/src/index.ts +++ b/libs/remix-ai-core/src/index.ts @@ -9,7 +9,7 @@ import { RemoteInferencer } from './inferencers/remote/remoteInference' import { OllamaInferencer } from './inferencers/local/ollamaInferencer' import { MCPInferencer } from './inferencers/mcp/mcpInferencer' import { RemixMCPServer, createRemixMCPServer } from './remix-mcp-server' -import { isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost } from './inferencers/local/ollama' +import { isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, resetOllamaHostOnSettingsChange } from './inferencers/local/ollama' import { FIMModelManager, FIMModelConfig, FIM_MODEL_CONFIGS } from './inferencers/local/fimModelConfig' import { ChatHistory } from './prompts/chat' import { downloadLatestReleaseExecutable } from './helpers/inferenceServerReleases' @@ -18,7 +18,7 @@ import { mcpDefaultServersConfig } from './config/mcpDefaultServers' export { IModel, IModelResponse, ChatCommandParser, ModelType, DefaultModels, ICompletions, IParams, IRemoteModel, buildChatPrompt, - RemoteInferencer, OllamaInferencer, MCPInferencer, RemixMCPServer, isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, + RemoteInferencer, OllamaInferencer, MCPInferencer, RemixMCPServer, isOllamaAvailable, getBestAvailableModel, listModels, discoverOllamaHost, resetOllamaHostOnSettingsChange, FIMModelManager, FIMModelConfig, FIM_MODEL_CONFIGS, createRemixMCPServer, InsertionParams, CompletionParams, GenerationParams, AssistantParams, ChatEntry, AIRequestType, ChatHistory, downloadLatestReleaseExecutable, diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 0702710aacb..067d7d56798 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import { Registry } from '@remix-project/remix-lib'; // Helper function to track events using MatomoManager instance function trackMatomoEvent(category: string, action: string, name?: string) { @@ -14,15 +15,47 @@ function trackMatomoEvent(category: string, action: string, name?: string) { // default Ollama ports to check (11434 is the legacy/standard port) const OLLAMA_PORTS = [11434, 11435, 11436]; const OLLAMA_BASE_HOST = 'http://localhost'; +const DEFAULT_OLLAMA_HOST = 'http://localhost:11434'; let discoveredOllamaHost: string | null = null; +function getConfiguredOllamaEndpoint(): string | null { + try { + const config = Registry.getInstance().get('config').api; + const configuredEndpoint = config.get('settings/ollama-endpoint'); + if (configuredEndpoint && configuredEndpoint !== DEFAULT_OLLAMA_HOST) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_using_configured_endpoint', configuredEndpoint]); + return configuredEndpoint; + } + } catch (error) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_config_access_failed', error.message || 'unknown']); + } + return null; +} + export async function discoverOllamaHost(): Promise { if (discoveredOllamaHost) { trackMatomoEvent('ai', 'remixAI', `ollama_host_cache_hit:${discoveredOllamaHost}`); return discoveredOllamaHost; } + // First, try to use the configured endpoint from settings + const configuredEndpoint = getConfiguredOllamaEndpoint(); + if (configuredEndpoint) { + try { + const res = await axios.get(`${configuredEndpoint}/api/tags`, { timeout: 2000 }); + if (res.status === 200) { + discoveredOllamaHost = configuredEndpoint; + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_success', configuredEndpoint]); + return configuredEndpoint; + } + } catch (error) { + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_failed', `${configuredEndpoint}:${error.message || 'unknown'}`]); + // Fall back to discovery if configured endpoint fails + } + } + + // Fall back to port discovery if no configured endpoint or it failed for (const port of OLLAMA_PORTS) { const host = `${OLLAMA_BASE_HOST}:${port}`; trackMatomoEvent('ai', 'remixAI', `ollama_port_check:${port}`); @@ -75,6 +108,12 @@ export function resetOllamaHost(): void { discoveredOllamaHost = null; } +export function resetOllamaHostOnSettingsChange(): void { + // This function should be called when Ollama settings are updated + resetOllamaHost(); + _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_reset_on_settings_change']); +} + export async function pullModel(modelName: string): Promise { // in case the user wants to pull a model from registry trackMatomoEvent('ai', 'remixAI', `ollama_pull_model_start:${modelName}`); diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index 31f4bf090ab..cd03c623d40 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -128,6 +128,16 @@ const settingsSections: SettingsSection[] = [ action: 'link', link: 'https://remix-ide.readthedocs.io/en/latest/ai.html' } + }, + { + name: 'ollama-config', + label: 'settings.ollamaConfig', + description: 'settings.ollamaConfigDescription', + type: 'toggle', + toggleUIOptions: [{ + name: 'ollama-endpoint', + type: 'text' + }] }] }, ...(mcpEnabled ? [{ diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 714d91bbb8b..0bea235b1cf 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -18,12 +18,14 @@ const sindriAccessToken = config.get('settings/sindri-access-token') || '' const etherscanAccessToken = config.get('settings/etherscan-access-token') || '' const mcpServersEnable = config.get('settings/mcp/servers/enable') || false const mcpServerManagement = config.get('settings/mcp-server-management') || false +const ollamaEndpoint = config.get('settings/ollama-endpoint') || 'http://localhost:11434' let githubConfig = config.get('settings/github-config') || false let ipfsConfig = config.get('settings/ipfs-config') || false let swarmConfig = config.get('settings/swarm-config') || false let sindriConfig = config.get('settings/sindri-config') || false let etherscanConfig = config.get('settings/etherscan-config') || false +let ollamaConfig = config.get('settings/ollama-config') || false let generateContractMetadata = config.get('settings/generate-contract-metadata') let autoCompletion = config.get('settings/auto-completion') let showGas = config.get('settings/show-gas') @@ -50,6 +52,10 @@ if (!etherscanConfig && etherscanAccessToken) { config.set('settings/etherscan-config', true) etherscanConfig = true } +if (!ollamaConfig && ollamaEndpoint !== 'http://localhost:11434') { + config.set('settings/ollama-config', true) + ollamaConfig = true +} if (typeof generateContractMetadata !== 'boolean') { config.set('settings/generate-contract-metadata', true) generateContractMetadata = true @@ -188,12 +194,21 @@ export const initialState: SettingsState = { value: '', isLoading: false }, +<<<<<<< HEAD 'mcp/servers/enable': { value: mcpServersEnable, isLoading: false }, 'mcp-server-management': { value: mcpServerManagement, +======= + 'ollama-config': { + value: ollamaConfig, + isLoading: false + }, + 'ollama-endpoint': { + value: ollamaEndpoint, +>>>>>>> 0571313a4a (initial endpoint) isLoading: false }, toaster: { @@ -206,6 +221,19 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S switch (action.type) { case 'SET_VALUE': config.set('settings/' + action.payload.name, action.payload.value) + + // Reset Ollama host cache when endpoint is changed + if (action.payload.name === 'ollama-endpoint') { + try { + // Check if the resetOllamaHostOnSettingsChange function is available globally + if (typeof window !== 'undefined' && (window as any).resetOllamaHostOnSettingsChange) { + (window as any).resetOllamaHostOnSettingsChange(); + } + } catch (error) { + // Ignore errors - Ollama functionality is optional + } + } + return { ...state, [action.payload.name]: { ...state[action.payload.name], value: action.payload.value, isLoading: false } } case 'SET_LOADING': return { ...state, [action.payload.name]: { ...state[action.payload.name], isLoading: true } } diff --git a/libs/remix-ui/settings/src/types/index.ts b/libs/remix-ui/settings/src/types/index.ts index 4473c994f6e..18e3f066e12 100644 --- a/libs/remix-ui/settings/src/types/index.ts +++ b/libs/remix-ui/settings/src/types/index.ts @@ -115,6 +115,8 @@ export interface SettingsState { 'ai-privacy-policy': ConfigState, 'mcp/servers/enable': ConfigState, 'mcp-server-management': ConfigState, + 'ollama-config': ConfigState, + 'ollama-endpoint': ConfigState, toaster: ConfigState } export interface SettingsActionPayloadTypes { From e015c26f78c66c8b7d56b21b6ba89cb65afcfda6 Mon Sep 17 00:00:00 2001 From: pipper Date: Wed, 10 Sep 2025 09:13:27 +0200 Subject: [PATCH 07/12] working on remote URL --- apps/remix-ide/src/app/tabs/locales/en/settings.json | 2 +- libs/remix-ai-core/src/inferencers/local/ollama.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/locales/en/settings.json b/apps/remix-ide/src/app/tabs/locales/en/settings.json index 3900d1a7d0a..8a7ddd83c57 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/settings.json +++ b/apps/remix-ide/src/app/tabs/locales/en/settings.json @@ -70,7 +70,7 @@ "settings.enableMCPEnhancement": "Enable MCP Integration", "settings.enableMCPEnhancementDescription": "Manage your MCP server connections", "settings.aiPrivacyPolicyDescription": "Understand how RemixAI processes your data.", - "settings.ollamaConfig": "Ollama Configuration", + "settings.ollamaConfig": "Ollama URL Configuration", "settings.ollamaConfigDescription": "Configure Ollama endpoint for local AI model integration", "settings.ollama-endpoint": "ENDPOINT URL" } diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 067d7d56798..5209023af51 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -49,13 +49,15 @@ export async function discoverOllamaHost(): Promise { _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_success', configuredEndpoint]); return configuredEndpoint; } + return null; } catch (error) { _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_failed', `${configuredEndpoint}:${error.message || 'unknown'}`]); // Fall back to discovery if configured endpoint fails + return null; } } - // Fall back to port discovery if no configured endpoint or it failed + // Fall back to port discovery if no configured endpoint for (const port of OLLAMA_PORTS) { const host = `${OLLAMA_BASE_HOST}:${port}`; trackMatomoEvent('ai', 'remixAI', `ollama_port_check:${port}`); From fcd7824fec26589a4c7dd8f218981ebacbe408a8 Mon Sep 17 00:00:00 2001 From: pipper Date: Thu, 11 Sep 2025 09:35:48 +0200 Subject: [PATCH 08/12] rm global function --- .gitignore | 6 +----- apps/remix-ide/src/app/plugins/remixAIPlugin.tsx | 4 +--- libs/remix-ui/settings/src/lib/settingsReducer.ts | 7 ++----- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index fff83ce6d98..83c04a65772 100644 --- a/.gitignore +++ b/.gitignore @@ -79,12 +79,8 @@ apps/remixdesktop/log_input_signals_new.txt logs apps/remix-ide-e2e/src/extensions/chrome/metamask apps/remix-ide-e2e/tmp/ -apps/remix-ide-e2e/tmp/ # IDE - Cursor -<<<<<<< HEAD -.cursor/ -======= .cursor/ PR_MESSAGE.md ->>>>>>> master +apps/remix-ide-e2e/tmp/ diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index 43f7cefc05d..c03cc584b73 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -64,9 +64,7 @@ export class RemixAIPlugin extends Plugin { onActivation(): void { // Expose Ollama reset function globally for settings integration - if (typeof window !== 'undefined') { - (window as any).resetOllamaHostOnSettingsChange = resetOllamaHostOnSettingsChange; - } + resetOllamaHostOnSettingsChange(); if (this.isOnDesktop) { this.useRemoteInferencer = true diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 0bea235b1cf..97514c9afcd 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -1,6 +1,6 @@ import { Registry } from '@remix-project/remix-lib' import { SettingsActions, SettingsState } from '../types' - +import { resetOllamaHostOnSettingsChange } from '@remix/remix-ai-core'; const config = Registry.getInstance().get('config').api const settingsConfig = Registry.getInstance().get('settingsConfig').api const defaultTheme = config.get('settings/theme') ? settingsConfig.themes.find((theme) => theme.name.toLowerCase() === config.get('settings/theme').toLowerCase()) : settingsConfig.themes[0] @@ -225,10 +225,7 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S // Reset Ollama host cache when endpoint is changed if (action.payload.name === 'ollama-endpoint') { try { - // Check if the resetOllamaHostOnSettingsChange function is available globally - if (typeof window !== 'undefined' && (window as any).resetOllamaHostOnSettingsChange) { - (window as any).resetOllamaHostOnSettingsChange(); - } + resetOllamaHostOnSettingsChange(); } catch (error) { // Ignore errors - Ollama functionality is optional } From 0a8b9e42cde8e31f0f93f22b5d94231586803be1 Mon Sep 17 00:00:00 2001 From: pipper Date: Mon, 13 Oct 2025 19:19:44 +0200 Subject: [PATCH 09/12] linting --- libs/remix-ui/settings/src/lib/settingsReducer.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 97514c9afcd..94eacad153a 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -221,7 +221,6 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S switch (action.type) { case 'SET_VALUE': config.set('settings/' + action.payload.name, action.payload.value) - // Reset Ollama host cache when endpoint is changed if (action.payload.name === 'ollama-endpoint') { try { @@ -230,7 +229,7 @@ export const settingReducer = (state: SettingsState, action: SettingsActions): S // Ignore errors - Ollama functionality is optional } } - + return { ...state, [action.payload.name]: { ...state[action.payload.name], value: action.payload.value, isLoading: false } } case 'SET_LOADING': return { ...state, [action.payload.name]: { ...state[action.payload.name], isLoading: true } } From f9b5759aa8a18fa3a2f0236419d177f6c3e97df3 Mon Sep 17 00:00:00 2001 From: STetsing <41009393+STetsing@users.noreply.github.com> Date: Fri, 24 Oct 2025 12:22:59 +0200 Subject: [PATCH 10/12] adding back _paq --- libs/remix-ai-core/src/inferencers/local/ollama.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 5209023af51..19ecdfa3697 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -1,5 +1,6 @@ import axios from 'axios'; import { Registry } from '@remix-project/remix-lib'; +const _paq = (window._paq = window._paq || []) // Helper function to track events using MatomoManager instance function trackMatomoEvent(category: string, action: string, name?: string) { From 634be9319bb4e96d7cdbc29804573961dcaebc2b Mon Sep 17 00:00:00 2001 From: ci-bot Date: Tue, 11 Nov 2025 12:20:39 +0100 Subject: [PATCH 11/12] fix matomo event && label --- .../src/inferencers/local/ollama.ts | 65 +++++++++---------- .../remix-ui-remix-ai-assistant.tsx | 4 +- .../settings/src/lib/settingsReducer.ts | 5 +- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/libs/remix-ai-core/src/inferencers/local/ollama.ts b/libs/remix-ai-core/src/inferencers/local/ollama.ts index 19ecdfa3697..64de03f1312 100644 --- a/libs/remix-ai-core/src/inferencers/local/ollama.ts +++ b/libs/remix-ai-core/src/inferencers/local/ollama.ts @@ -1,17 +1,6 @@ import axios from 'axios'; import { Registry } from '@remix-project/remix-lib'; -const _paq = (window._paq = window._paq || []) - -// Helper function to track events using MatomoManager instance -function trackMatomoEvent(category: string, action: string, name?: string) { - try { - if (typeof window !== 'undefined' && (window as any)._matomoManagerInstance) { - (window as any)._matomoManagerInstance.trackEvent(category, action, name) - } - } catch (error) { - // Silent fail for tracking - } -} +import { trackMatomoEvent } from '@remix-api' // default Ollama ports to check (11434 is the legacy/standard port) const OLLAMA_PORTS = [11434, 11435, 11436]; @@ -21,22 +10,24 @@ const DEFAULT_OLLAMA_HOST = 'http://localhost:11434'; let discoveredOllamaHost: string | null = null; function getConfiguredOllamaEndpoint(): string | null { + const filemanager = Registry.getInstance().get('filemanager').api; try { - const config = Registry.getInstance().get('config').api; + const config = Registry.getInstance().get('config').api const configuredEndpoint = config.get('settings/ollama-endpoint'); if (configuredEndpoint && configuredEndpoint !== DEFAULT_OLLAMA_HOST) { - _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_using_configured_endpoint', configuredEndpoint]); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_using_configured_endpoint', value: configuredEndpoint }); return configuredEndpoint; } } catch (error) { - _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_config_access_failed', error.message || 'unknown']); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_config_access_failed', value: error.message || 'unknown' }); } return null; } export async function discoverOllamaHost(): Promise { + const filemanager = Registry.getInstance().get('filemanager').api; if (discoveredOllamaHost) { - trackMatomoEvent('ai', 'remixAI', `ollama_host_cache_hit:${discoveredOllamaHost}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_host_cache_hit:${discoveredOllamaHost}` }) return discoveredOllamaHost; } @@ -47,12 +38,12 @@ export async function discoverOllamaHost(): Promise { const res = await axios.get(`${configuredEndpoint}/api/tags`, { timeout: 2000 }); if (res.status === 200) { discoveredOllamaHost = configuredEndpoint; - _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_success', configuredEndpoint]); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_configured_endpoint_success', value: configuredEndpoint }); return configuredEndpoint; } return null; } catch (error) { - _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_configured_endpoint_failed', `${configuredEndpoint}:${error.message || 'unknown'}`]); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_configured_endpoint_failed', value: `${configuredEndpoint}:${error.message || 'unknown'}` }); // Fall back to discovery if configured endpoint fails return null; } @@ -61,36 +52,38 @@ export async function discoverOllamaHost(): Promise { // Fall back to port discovery if no configured endpoint for (const port of OLLAMA_PORTS) { const host = `${OLLAMA_BASE_HOST}:${port}`; - trackMatomoEvent('ai', 'remixAI', `ollama_port_check:${port}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_port_check:${port}` }); try { const res = await axios.get(`${host}/api/tags`, { timeout: 2000 }); if (res.status === 200) { discoveredOllamaHost = host; - trackMatomoEvent('ai', 'remixAI', `ollama_host_discovered_success:${host}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_host_discovered_success:${host}` }); return host; } } catch (error) { - trackMatomoEvent('ai', 'remixAI', `ollama_port_connection_failed:${port}:${error.message || 'unknown'}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_port_connection_failed:${port}:${error.message || 'unknown'}` }); continue; // next port } } - trackMatomoEvent('ai', 'remixAI', 'ollama_host_discovery_failed:no_ports_available'); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_host_discovery_failed:no_ports_available' }); return null; } export async function isOllamaAvailable(): Promise { - trackMatomoEvent('ai', 'remixAI', 'ollama_availability_check:checking'); + const filemanager = Registry.getInstance().get('filemanager').api; + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_availability_check:checking' }); const host = await discoverOllamaHost(); const isAvailable = host !== null; - trackMatomoEvent('ai', 'remixAI', `ollama_availability_result:available:${isAvailable}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_availability_result:available:${isAvailable}` }); return isAvailable; } export async function listModels(): Promise { - trackMatomoEvent('ai', 'remixAI', 'ollama_list_models_start:fetching'); + const filemanager = Registry.getInstance().get('filemanager').api; + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_list_models_start:fetching' }); const host = await discoverOllamaHost(); if (!host) { - trackMatomoEvent('ai', 'remixAI', 'ollama_list_models_failed:no_host'); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_list_models_failed:no_host' }); throw new Error('Ollama is not available'); } @@ -107,22 +100,25 @@ export function getOllamaHost(): string | null { } export function resetOllamaHost(): void { - trackMatomoEvent('ai', 'remixAI', `ollama_reset_host:${discoveredOllamaHost || 'null'}`); + const fileManager = Registry.getInstance().get('filemanager').api; + trackMatomoEvent(fileManager, { category: 'ai', action: 'remixAI', name: `ollama_reset_host:${discoveredOllamaHost || 'null'}` }); discoveredOllamaHost = null; } export function resetOllamaHostOnSettingsChange(): void { + const fileManager = Registry.getInstance().get('filemanager').api; // This function should be called when Ollama settings are updated resetOllamaHost(); - _paq.push(['trackEvent', 'ai', 'remixAI', 'ollama_reset_on_settings_change']); + trackMatomoEvent(fileManager, { category: 'ai', action: 'remixAI', name: 'ollama_reset_on_settings_change' }); } export async function pullModel(modelName: string): Promise { + const filemanager = Registry.getInstance().get('filemanager').api; // in case the user wants to pull a model from registry - trackMatomoEvent('ai', 'remixAI', `ollama_pull_model_start:${modelName}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_pull_model_start:${modelName}` }); const host = await discoverOllamaHost(); if (!host) { - trackMatomoEvent('ai', 'remixAI', `ollama_pull_model_failed:${modelName}|no_host`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_pull_model_failed:${modelName}|no_host` }); throw new Error('Ollama is not available'); } @@ -130,9 +126,9 @@ export async function pullModel(modelName: string): Promise { const startTime = Date.now(); await axios.post(`${host}/api/pull`, { name: modelName }); const duration = Date.now() - startTime; - trackMatomoEvent('ai', 'remixAI', `ollama_pull_model_success:${modelName}|duration:${duration}ms`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_pull_model_success:${modelName}|duration:${duration}ms` }); } catch (error) { - trackMatomoEvent('ai', 'remixAI', `ollama_pull_model_error:${modelName}|${error.message || 'unknown'}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_pull_model_error:${modelName}|${error.message || 'unknown'}` }); console.error('Error pulling model:', error); throw new Error(`Failed to pull model: ${modelName}`); } @@ -148,7 +144,8 @@ export async function validateModel(modelName: string): Promise { } export async function getBestAvailableModel(): Promise { - trackMatomoEvent('ai', 'remixAI', 'ollama_get_best'); + const filemanager = Registry.getInstance().get('filemanager').api; + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: 'ollama_get_best' }); try { const models = await listModels(); if (models.length === 0) return null; @@ -167,7 +164,7 @@ export async function getBestAvailableModel(): Promise { // TODO get model stats and get best model return models[0]; } catch (error) { - trackMatomoEvent('ai', 'remixAI', `ollama_get_best_model_error:${error.message || 'unknown'}`); + trackMatomoEvent(filemanager, { category: 'ai', action: 'remixAI', name: `ollama_get_best_model_error:${error.message || 'unknown'}` }); console.error('Error getting best available model:', error); return null; } diff --git a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx index ab795655f4e..c76d3a2e45f 100644 --- a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx +++ b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx @@ -645,7 +645,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< setMessages(prev => [...prev, { id: crypto.randomUUID(), role: 'assistant', - content: '**Ollama is not available.**\n\nTo use Ollama with Remix IDE:\n\n1. **Install Ollama**: Visit [ollama.ai](https://ollama.ai) to download\n2. **Start Ollama**: Run `ollama serve` in your terminal\n3. **Install a model**: Run `ollama pull codestral:latest`\n4. **Configure CORS**: Set `OLLAMA_ORIGINS=https://remix.ethereum.org`\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for detailed instructions.\n\n*Switching back to previous model for now.*', + content: '**Ollama is not available.**\n\nTo use Ollama with Remix IDE:\n\n1. **Install Ollama**: Visit [ollama.ai](https://ollama.ai) to download\n2. **Start Ollama**: Run `ollama serve` in your terminal\n3. **Install a model**: Run `ollama pull codestral:latest`\n4. **Configure CORS**: e.g \`OLLAMA_ORIGINS=https://remix.ethereum.org ollama serve\`\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for detailed instructions.\n\n*Switching back to previous model for now.*', timestamp: Date.now(), sentiment: 'none' }]) @@ -662,7 +662,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< setMessages(prev => [...prev, { id: crypto.randomUUID(), role: 'assistant', - content: `**Failed to connect to Ollama.**\n\nError: ${error.message || 'Unknown error'}\n\nPlease ensure:\n- Ollama is running (\`ollama serve\`)\n- CORS is configured for Remix IDE\n- At least one model is installed\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for help.\n\n*Switching back to previous model.*`, + content: `**Failed to connect to Ollama.**\n\nError: ${error.message || 'Unknown error'}\n\nPlease ensure:\n- Ollama is running (\`ollama serve\`)\n- The ollama CORS setting is configured for Remix IDE. e.g \`OLLAMA_ORIGINS=https://remix.ethereum.org ollama serve\` Please see [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for detailed instructions.\n- At least one model is installed\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for help.\n\n*Switching back to previous model.*`, timestamp: Date.now(), sentiment: 'none' }]) diff --git a/libs/remix-ui/settings/src/lib/settingsReducer.ts b/libs/remix-ui/settings/src/lib/settingsReducer.ts index 94eacad153a..a983bd91b2c 100644 --- a/libs/remix-ui/settings/src/lib/settingsReducer.ts +++ b/libs/remix-ui/settings/src/lib/settingsReducer.ts @@ -194,21 +194,20 @@ export const initialState: SettingsState = { value: '', isLoading: false }, -<<<<<<< HEAD 'mcp/servers/enable': { value: mcpServersEnable, isLoading: false }, 'mcp-server-management': { value: mcpServerManagement, -======= + isLoading: false + }, 'ollama-config': { value: ollamaConfig, isLoading: false }, 'ollama-endpoint': { value: ollamaEndpoint, ->>>>>>> 0571313a4a (initial endpoint) isLoading: false }, toaster: { From 20252db1440bccec7f9beca70774d82dab448a56 Mon Sep 17 00:00:00 2001 From: pipper Date: Wed, 26 Nov 2025 11:31:02 +0100 Subject: [PATCH 12/12] linting libs --- .../src/components/remix-ui-remix-ai-assistant.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx index da239070d94..f075421eab2 100644 --- a/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx +++ b/libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx @@ -654,7 +654,7 @@ export const RemixUiRemixAiAssistant = React.forwardRef< setMessages(prev => [...prev, { id: crypto.randomUUID(), role: 'assistant', - content: '**Ollama is not available.**\n\nTo use Ollama with Remix IDE:\n\n1. **Install Ollama**: Visit [ollama.ai](https://ollama.ai) to download\n2. **Start Ollama**: Run `ollama serve` in your terminal\n3. **Install a model**: Run `ollama pull codestral:latest`\n4. **Configure CORS**: e.g \`OLLAMA_ORIGINS=https://remix.ethereum.org ollama serve\`\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for detailed instructions.\n\n*Switching back to previous model for now.*', + content: '**Ollama is not available.**\n\nTo use Ollama with Remix IDE:\n\n1. **Install Ollama**: Visit [ollama.ai](https://ollama.ai) to download\n2. **Start Ollama**: Run `ollama serve` in your terminal\n3. **Install a model**: Run `ollama pull codestral:latest`\n4. **Configure CORS**: e.g `OLLAMA_ORIGINS=https://remix.ethereum.org ollama serve`\n\nSee the [Ollama Setup Guide](https://github.com/ethereum/remix-project/blob/master/OLLAMA_SETUP.md) for detailed instructions.\n\n*Switching back to previous model for now.*', timestamp: Date.now(), sentiment: 'none' }])