@@ -15,6 +15,7 @@ import { FileActionManager } from '../actions/filesystem.js';
1515import { saveConfig , getProviderConfig } from '../config.js' ;
1616import type { LLMProvider } from '../providers/LLMProvider.js' ;
1717import { ProviderFactory , ProviderNotConfiguredError } from '../providers/ProviderFactory.js' ;
18+ import { isMLXSupported } from '../utils/platform.js' ;
1819import { readInstruction } from '../ui/inputPrompt.js' ;
1920// showFilePalette is imported dynamically to avoid bundling ink in standalone binary
2021import {
@@ -238,7 +239,10 @@ export class AutohandAgent {
238239 }
239240 } ) ;
240241 this . errorLogger = new ErrorLogger ( packageJson . version ) ;
241- this . feedbackManager = new FeedbackManager ( ) ;
242+ this . feedbackManager = new FeedbackManager ( {
243+ apiBaseUrl : runtime . config . api ?. baseUrl || 'https://api.autohand.ai' ,
244+ cliVersion : packageJson . version
245+ } ) ;
242246 this . skillsRegistry = new SkillsRegistry ( AUTOHAND_PATHS . skills ) ;
243247 this . telemetryManager = new TelemetryManager ( {
244248 enabled : runtime . config . telemetry ?. enabled === true ,
@@ -1018,14 +1022,17 @@ If lint or tests fail, report the issues but do NOT commit.`;
10181022 private async promptModelSelection ( ) : Promise < void > {
10191023 try {
10201024 // Show all providers with status indicators
1021- const allProviders : ProviderName [ ] = [ 'openrouter' , 'ollama' , 'llamacpp' , 'openai' ] ;
1025+ // Use ProviderFactory to get platform-aware list (includes MLX on Apple Silicon)
1026+ const allProviders = ProviderFactory . getProviderNames ( ) ;
10221027 const providerChoices = allProviders . map ( name => {
10231028 const isConfigured = this . isProviderConfigured ( name ) ;
10241029 const indicator = isConfigured ? chalk . green ( '●' ) : chalk . red ( '○' ) ;
10251030 const current = name === this . activeProvider ? chalk . cyan ( ' (current)' ) : '' ;
1031+ // Add Apple Silicon indicator for MLX
1032+ const siliconNote = name === 'mlx' ? chalk . gray ( ' (Apple Silicon)' ) : '' ;
10261033 return {
10271034 name,
1028- message : `${ indicator } ${ name } ${ current } ` ,
1035+ message : `${ indicator } ${ name } ${ current } ${ siliconNote } ` ,
10291036 value : name
10301037 } ;
10311038 } ) ;
@@ -1088,6 +1095,9 @@ If lint or tests fail, report the issues but do NOT commit.`;
10881095 case 'openai' :
10891096 await this . configureOpenAI ( ) ;
10901097 break ;
1098+ case 'mlx' :
1099+ await this . configureMLX ( ) ;
1100+ break ;
10911101 }
10921102 }
10931103
@@ -1281,6 +1291,67 @@ If lint or tests fail, report the issues but do NOT commit.`;
12811291 }
12821292 }
12831293
1294+ private async configureMLX ( ) : Promise < void > {
1295+ try {
1296+ console . log ( chalk . cyan ( 'MLX Configuration (Apple Silicon)' ) ) ;
1297+ console . log ( chalk . gray ( 'MLX provides local LLM inference optimized for Apple Silicon.' ) ) ;
1298+ console . log ( chalk . gray ( 'Make sure mlx-lm server is running: mlx_lm.server --model <model-name>\n' ) ) ;
1299+
1300+ // Try to fetch available models from MLX server
1301+ const mlxUrl = 'http://localhost:8080' ;
1302+ let availableModels : string [ ] = [ ] ;
1303+
1304+ try {
1305+ const response = await fetch ( `${ mlxUrl } /v1/models` ) ;
1306+ if ( response . ok ) {
1307+ const data = await response . json ( ) ;
1308+ availableModels = data . data ?. map ( ( m : any ) => m . id ) || [ ] ;
1309+ }
1310+ } catch {
1311+ console . log ( chalk . yellow ( '⚠ Could not connect to MLX server. Make sure it\'s running.\n' ) ) ;
1312+ }
1313+
1314+ let modelAnswer ;
1315+ if ( availableModels . length > 0 ) {
1316+ modelAnswer = await enquirer . prompt < { model : string } > ( [
1317+ {
1318+ type : 'select' ,
1319+ name : 'model' ,
1320+ message : 'Select a model' ,
1321+ choices : availableModels
1322+ }
1323+ ] ) ;
1324+ } else {
1325+ modelAnswer = await enquirer . prompt < { model : string } > ( [
1326+ {
1327+ type : 'input' ,
1328+ name : 'model' ,
1329+ message : 'Enter model name (e.g., mlx-community/Llama-3.2-3B-Instruct-4bit)' ,
1330+ initial : 'mlx-community/Llama-3.2-3B-Instruct-4bit'
1331+ }
1332+ ] ) ;
1333+ }
1334+
1335+ this . runtime . config . mlx = {
1336+ baseUrl : mlxUrl ,
1337+ model : modelAnswer . model
1338+ } ;
1339+
1340+ this . runtime . config . provider = 'mlx' ;
1341+ this . runtime . options . model = modelAnswer . model ;
1342+ await saveConfig ( this . runtime . config ) ;
1343+ this . resetLlmClient ( 'mlx' , modelAnswer . model ) ;
1344+
1345+ console . log ( chalk . green ( '\n✓ MLX configured successfully!' ) ) ;
1346+ } catch ( error ) {
1347+ if ( ( error as any ) . name === 'ExitPromptError' || ( error as Error ) . message ?. includes ( 'canceled' ) ) {
1348+ console . log ( chalk . gray ( '\nConfiguration cancelled.' ) ) ;
1349+ return ;
1350+ }
1351+ throw error ;
1352+ }
1353+ }
1354+
12841355 private async changeProviderModel ( provider : ProviderName ) : Promise < void > {
12851356 try {
12861357 const currentSettings = getProviderConfig ( this . runtime . config , provider ) ;
@@ -3956,6 +4027,7 @@ If lint or tests fail, report the issues but do NOT commit.`;
39564027 if ( this . runtime . config . ollama ) providers . push ( 'ollama' ) ;
39574028 if ( this . runtime . config . llamacpp ) providers . push ( 'llamacpp' ) ;
39584029 if ( this . runtime . config . openai ) providers . push ( 'openai' ) ;
4030+ if ( this . runtime . config . mlx ) providers . push ( 'mlx' ) ;
39594031 return providers . length ? providers : [ 'openrouter' ] ;
39604032 }
39614033
@@ -3964,7 +4036,8 @@ If lint or tests fail, report the issues but do NOT commit.`;
39644036 openrouter : this . runtime . config . openrouter ?? ( this . runtime . config . openrouter = { apiKey : '' , model } ) ,
39654037 ollama : this . runtime . config . ollama ?? ( this . runtime . config . ollama = { model } ) ,
39664038 llamacpp : this . runtime . config . llamacpp ?? ( this . runtime . config . llamacpp = { model } ) ,
3967- openai : this . runtime . config . openai ?? ( this . runtime . config . openai = { model } )
4039+ openai : this . runtime . config . openai ?? ( this . runtime . config . openai = { model } ) ,
4040+ mlx : this . runtime . config . mlx ?? ( this . runtime . config . mlx = { model } )
39684041 } ;
39694042 cfgMap [ provider ] . model = model ;
39704043 this . activeProvider = provider ;
0 commit comments