@@ -45,13 +45,16 @@ struct PerspectiveCLI {
4545enum CLIError : LocalizedError {
4646 case sessionNotInitialized
4747 case backendUnavailable( String )
48+ case adapterNotFound( String )
4849
4950 var errorDescription : String ? {
5051 switch self {
5152 case . sessionNotInitialized:
5253 return " Session not initialized. Try /reset to reinitialize. "
5354 case . backendUnavailable( let reason) :
5455 return " Backend unavailable: \( reason) "
56+ case . adapterNotFound( let path) :
57+ return " Adapter file not found: \( path) "
5558 }
5659 }
5760}
@@ -66,6 +69,7 @@ struct CLIArguments {
6669 var stream : Bool = false
6770 var systemPrompt : String ?
6871 var tools : Bool = false
72+ var adapter : String ?
6973 var help : Bool = false
7074
7175 init ( ) {
@@ -89,6 +93,8 @@ struct CLIArguments {
8993 systemPrompt = iter. next ( )
9094 case " --tools " :
9195 tools = true
96+ case " --adapter " :
97+ adapter = iter. next ( )
9298 case " --help " , " -h " :
9399 help = true
94100 default :
@@ -147,6 +153,14 @@ actor CLIApp {
147153 if let model = args. mlxModel {
148154 await mlxBackend. setModelId ( model)
149155 }
156+ if let adapterPath = args. adapter {
157+ do {
158+ try await fmBackend. loadAdapter ( from: adapterPath)
159+ printSuccess ( " Adapter loaded: \( adapterPath) " )
160+ } catch {
161+ printError ( " Failed to load adapter: \( error. localizedDescription) " )
162+ }
163+ }
150164 }
151165
152166 /// Initialize the active backend, returning true on success.
@@ -159,7 +173,12 @@ actor CLIApp {
159173 return false
160174 }
161175 if !quiet { printSuccess ( msg) }
162- await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
176+ do {
177+ try await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
178+ } catch {
179+ printError ( " Failed to initialize FM: \( error. localizedDescription) " )
180+ return false
181+ }
163182 if !quiet { printSuccess ( " FM session initialized " ) }
164183 return true
165184 case . mlx:
@@ -237,8 +256,12 @@ actor CLIApp {
237256
238257 // Initialize FM backend if available
239258 if fmAvailable && activeBackend == . fm {
240- await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
241- printSuccess ( " FM session initialized " )
259+ do {
260+ try await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
261+ printSuccess ( " FM session initialized " )
262+ } catch {
263+ printError ( " Failed to initialize FM: \( error. localizedDescription) " )
264+ }
242265 }
243266
244267 // Initialize MLX backend if selected via args
@@ -306,8 +329,12 @@ actor CLIApp {
306329 switch activeBackend {
307330 case . fm:
308331 await fmBackend. resetSession ( )
309- await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
310- printSuccess ( " FM conversation reset " )
332+ do {
333+ try await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
334+ printSuccess ( " FM conversation reset " )
335+ } catch {
336+ printError ( " Failed to reinitialize FM: \( error. localizedDescription) " )
337+ }
311338 case . mlx:
312339 await mlxBackend. resetSession ( )
313340 do {
@@ -330,8 +357,12 @@ actor CLIApp {
330357 activeBackend = . fm
331358 let ( available, _) = FoundationModelsBackend . checkAvailability ( )
332359 if available {
333- await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
334- printSuccess ( " Switched to Foundation Models backend " )
360+ do {
361+ try await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
362+ printSuccess ( " Switched to Foundation Models backend " )
363+ } catch {
364+ printError ( " Failed to initialize FM: \( error. localizedDescription) " )
365+ }
335366 } else {
336367 printError ( " Foundation Models not available on this device " )
337368 activeBackend = . mlx
@@ -452,6 +483,39 @@ actor CLIApp {
452483 printWarning ( " Invalid temperature. Use a value between 0.0 and \( maxTemp) " )
453484 }
454485
486+ case " /adapter " :
487+ if let path = await fmBackend. currentAdapterPath ( ) {
488+ printInfo ( " Current adapter: \( path) " )
489+ } else {
490+ printInfo ( " No adapter loaded " )
491+ }
492+
493+ case " /adapter clear " :
494+ await fmBackend. clearAdapter ( )
495+ printSuccess ( " Adapter cleared " )
496+ if activeBackend == . fm {
497+ await reinitializeActiveBackend ( )
498+ }
499+
500+ case _ where cmd. hasPrefix ( " /adapter " ) :
501+ let path = String ( command. dropFirst ( " /adapter " . count) )
502+ . trimmingCharacters ( in: . whitespacesAndNewlines)
503+ if path. isEmpty {
504+ printWarning ( " Usage: /adapter <path-to-.fmadapter> " )
505+ } else {
506+ let resolved = NSString ( string: path) . expandingTildeInPath
507+ do {
508+ try await fmBackend. loadAdapter ( from: resolved)
509+ printSuccess ( " Adapter loaded: \( resolved) " )
510+ if activeBackend == . fm {
511+ printInfo ( " Reinitializing FM session with adapter... " )
512+ await reinitializeActiveBackend ( )
513+ }
514+ } catch {
515+ printError ( " Failed to load adapter: \( error. localizedDescription) " )
516+ }
517+ }
518+
455519 case " /status " :
456520 printInfo ( " Perspective CLI Status " )
457521 printInfo ( " ───────────────────── " )
@@ -470,6 +534,12 @@ actor CLIApp {
470534 printInfo ( " FM temperature: \( fmTemp) " )
471535 printInfo ( " FM streaming: \( fmStream ? " on " : " off " ) " )
472536 printInfo ( " Tools: \( toolsEnabled ? " enabled " : " disabled " ) " )
537+ // Adapter
538+ if let adapterPath = await fmBackend. currentAdapterPath ( ) {
539+ printInfo ( " FM adapter: \( adapterPath) " )
540+ } else {
541+ printInfo ( " FM adapter: none " )
542+ }
473543 // MLX settings
474544 let mlxModel = await mlxBackend. getModelId ( )
475545 let mlxTemp = await mlxBackend. getTemperature ( )
@@ -497,8 +567,12 @@ actor CLIApp {
497567 switch activeBackend {
498568 case . fm:
499569 await fmBackend. resetSession ( )
500- await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
501- printSuccess ( " FM session reinitialized " )
570+ do {
571+ try await fmBackend. initialize ( customPrompt: customSystemPrompt, enableTools: toolsEnabled)
572+ printSuccess ( " FM session reinitialized " )
573+ } catch {
574+ printError ( " Failed to reinitialize FM: \( error. localizedDescription) " )
575+ }
502576 case . mlx:
503577 await mlxBackend. resetSession ( )
504578 do {
@@ -582,6 +656,9 @@ func printHelp() {
582656 printInfo ( " /system clear - Clear custom system prompt " )
583657 printInfo ( " /temperature <n> - Set temperature (FM: 0.0-1.0, MLX: 0.0-2.0) " )
584658 printInfo ( " /stream - Toggle streaming (FM only) " )
659+ printInfo ( " /adapter <path> - Load a .fmadapter file (FM only) " )
660+ printInfo ( " /adapter - Show current adapter " )
661+ printInfo ( " /adapter clear - Remove loaded adapter " )
585662 printInfo ( " /tools - Show tool status and list " )
586663 printInfo ( " /tools enable - Enable tool calling (FM only) " )
587664 printInfo ( " /tools disable - Disable tool calling " )
@@ -619,6 +696,7 @@ func printUsage() {
619696 print ( " -s, --stream Enable streaming output (FM) " )
620697 print ( " --system <text> Set a custom system prompt " )
621698 print ( " --tools Enable tool calling (FM) " )
699+ print ( " --adapter <path> Load a .fmadapter file (FM) " )
622700 print ( " -h, --help Show this help " )
623701 print ( " " )
624702 print ( " Examples: " )
0 commit comments