@@ -25,10 +25,35 @@ import FoundationModels
2525#endif
2626
2727class LocalAIImpl : LocalAIApi {
28+ private static var _isModelReady : Bool ?
29+
2830 func isAvailable( completion: @escaping ( Result < Bool , Error > ) -> Void ) {
2931 #if canImport(FoundationModels)
3032 if #available( iOS 26 . 0 , macOS 26 . 0 , * ) {
31- completion ( . success( true ) )
33+ if let ready = LocalAIImpl . _isModelReady {
34+ completion ( . success( ready) )
35+ return
36+ }
37+
38+ let model = FoundationModels . SystemLanguageModel. default
39+ guard model. isAvailable else {
40+ LocalAIImpl . _isModelReady = false
41+ completion ( . success( false ) )
42+ return
43+ }
44+
45+ // Perform a lightweight check to verify the model is actually loadable and functional
46+ Task {
47+ do {
48+ let session = FoundationModels . LanguageModelSession ( model: model)
49+ _ = try await session. respond ( to: Prompt ( " Hello " ) )
50+ LocalAIImpl . _isModelReady = true
51+ completion ( . success( true ) )
52+ } catch {
53+ LocalAIImpl . _isModelReady = false
54+ completion ( . success( false ) )
55+ }
56+ }
3257 } else {
3358 completion ( . success( false ) )
3459 }
@@ -42,7 +67,22 @@ class LocalAIImpl: LocalAIApi {
4267 if #available( iOS 26 . 0 , macOS 26 . 0 , * ) {
4368 Task {
4469 do {
45- completion ( . success( " Local response from FoundationModels for: \( prompt) " ) )
70+ let model = FoundationModels . SystemLanguageModel. default
71+ guard model. isAvailable else {
72+ completion ( . failure( PigeonError ( code: " UNAVAILABLE " , message: " SystemLanguageModel is not available on this device " , details: nil ) ) )
73+ return
74+ }
75+ let session = FoundationModels . LanguageModelSession ( model: model)
76+ let response = try await session. respond ( to: Prompt ( prompt) )
77+ let content = response. rawContent
78+
79+ let responseText : String
80+ if case let . string( text) = content. kind {
81+ responseText = text
82+ } else {
83+ responseText = content. jsonString
84+ }
85+ completion ( . success( responseText) )
4686 } catch {
4787 completion ( . failure( error) )
4888 }
@@ -64,9 +104,24 @@ class LocalAIImpl: LocalAIApi {
64104 if #available( iOS 26 . 0 , macOS 26 . 0 , * ) {
65105 Task {
66106 do {
67- // Simulate streaming by sending chunks to the shared stream handler.
68- LocalAIStreamHandler . shared. sendEvent ( " Local chunk 1 for: \( prompt) " )
69- LocalAIStreamHandler . shared. sendEvent ( " Local chunk 2 for: \( prompt) " )
107+ let model = FoundationModels . SystemLanguageModel. default
108+ guard model. isAvailable else {
109+ completion ( . failure( PigeonError ( code: " UNAVAILABLE " , message: " SystemLanguageModel is not available on this device " , details: nil ) ) )
110+ return
111+ }
112+ let session = FoundationModels . LanguageModelSession ( model: model)
113+ let stream = session. streamResponse ( to: Prompt ( prompt) )
114+
115+ for try await snapshot in stream {
116+ let content = snapshot. rawContent
117+ let chunkText : String
118+ if case let . string( text) = content. kind {
119+ chunkText = text
120+ } else {
121+ chunkText = content. jsonString
122+ }
123+ LocalAIStreamHandler . shared. sendEvent ( chunkText)
124+ }
70125 LocalAIStreamHandler . shared. closeStream ( )
71126 completion ( . success( ( ) ) )
72127 } catch {
0 commit comments