@@ -265,24 +265,83 @@ private func formatErrorDescription(_ error: Error, function: String = #function
265265
266266// MARK: - Session response
267267
268+ // Helper function to parse GenerationOptions from JSON
269+ private func parseGenerationOptions( from jsonString: String ? ) throws -> GenerationOptions ? {
270+ guard let jsonString = jsonString, !jsonString. isEmpty else {
271+ return nil
272+ }
273+
274+ let data = Data ( jsonString. utf8)
275+ guard let json = try JSONSerialization . jsonObject ( with: data) as? [ String : Any ] else {
276+ throw NSError (
277+ domain: " GenerationOptions " ,
278+ code: - 1 ,
279+ userInfo: [ NSLocalizedDescriptionKey: " Invalid JSON " ]
280+ )
281+ }
282+
283+ var options = GenerationOptions ( )
284+
285+ // Parse sampling mode
286+ if let samplingDict = json [ " sampling " ] as? [ String : Any ] ,
287+ let mode = samplingDict [ " mode " ] as? String
288+ {
289+ switch mode {
290+ case " greedy " :
291+ options. sampling = . greedy
292+ case " random " :
293+ let seed = samplingDict [ " seed " ] as? UInt64
294+ // Swift API supports either topK or probabilityThreshold, not both
295+ if let topK = samplingDict [ " top_k " ] as? Int {
296+ options. sampling = . random( top: topK, seed: seed)
297+ } else if let probabilityThreshold = samplingDict [ " top_p " ] as? Double {
298+ options. sampling = . random( probabilityThreshold: probabilityThreshold, seed: seed)
299+ }
300+ default :
301+ break
302+ }
303+ }
304+
305+ // Parse temperature
306+ if let temperature = json [ " temperature " ] as? Double {
307+ options. temperature = temperature
308+ }
309+
310+ // Parse maximum_response_tokens
311+ if let maxTokens = json [ " maximum_response_tokens " ] as? Int {
312+ options. maximumResponseTokens = maxTokens
313+ }
314+
315+ return options
316+ }
317+
268318@_cdecl ( " FMLanguageModelSessionRespond " )
269319public func FMLanguageModelSessionRespond(
270320 session: FMLanguageModelSessionRef ,
271321 prompt: UnsafePointer < CChar > ,
322+ optionsJSON: UnsafePointer < CChar > ? ,
272323 userInfo: UnsafeMutableRawPointer ? ,
273324 callback: FMLanguageModelSessionResponseCallback
274325) -> FMTaskRef {
275326 let session = Unmanaged < LanguageModelSession > . fromOpaque ( session) . takeUnretainedValue ( )
276327 let unsafeSendableUserInfo = UnsafeSendableUserInfo ( pointer: userInfo)
277328
278- let prompt = String ( cString: prompt)
329+ let promptString = String ( cString: prompt)
330+ let optionsJSONString = optionsJSON. map ( String . init ( cString: ) )
331+
279332 let task = Task . detached {
280333 do {
281334 // Check cancellation at start
282335 try Task . checkCancellation ( )
283336
284- // Perform the expensive operation
285- let response = try await session. respond ( to: prompt)
337+ // Parse options if provided
338+ let options = try parseGenerationOptions ( from: optionsJSONString)
339+
340+ // Perform the expensive operation with options
341+ let response = try await session. respond (
342+ to: promptString,
343+ options: options ?? GenerationOptions ( )
344+ )
286345
287346 // Check cancellation before callback
288347 try Task . checkCancellation ( )
@@ -349,13 +408,22 @@ private final class UnsafeSendableResponseStreamBox<Content: Generable>: @unchec
349408@_cdecl ( " FMLanguageModelSessionStreamResponse " )
350409public func FMLanguageModelSessionStreamResponse(
351410 session: FMLanguageModelSessionRef ,
352- prompt: UnsafePointer < CChar >
411+ prompt: UnsafePointer < CChar > ,
412+ optionsJSON: UnsafePointer < CChar > ?
353413) -> FMLanguageModelSessionResponseStreamRef ? {
354414 let session = Unmanaged < LanguageModelSession > . fromOpaque ( session) . takeUnretainedValue ( )
355- let prompt = String ( cString: prompt)
356- let stream = session. streamResponse ( to: prompt)
357- let box = UnsafeSendableResponseStreamBox < String > ( stream: stream, session: session)
358- return FMLanguageModelSessionResponseStreamRef ( Unmanaged . passRetained ( box) . toOpaque ( ) )
415+ let promptString = String ( cString: prompt)
416+ let optionsJSONString = optionsJSON. map ( String . init ( cString: ) )
417+
418+ do {
419+ let options = try parseGenerationOptions ( from: optionsJSONString)
420+ let stream = session. streamResponse ( to: promptString, options: options ?? GenerationOptions ( ) )
421+ let box = UnsafeSendableResponseStreamBox < String > ( stream: stream, session: session)
422+ return FMLanguageModelSessionResponseStreamRef ( Unmanaged . passRetained ( box) . toOpaque ( ) )
423+ } catch {
424+ // If parsing fails, return nil
425+ return nil
426+ }
359427}
360428
361429@_cdecl ( " FMLanguageModelSessionResponseStreamIterate " )
@@ -439,12 +507,14 @@ public func FMLanguageModelSessionRespondWithSchema(
439507 session: FMLanguageModelSessionRef ,
440508 prompt: UnsafePointer < CChar > ,
441509 schema: FMGenerationSchemaRef ,
510+ optionsJSON: UnsafePointer < CChar > ? ,
442511 userInfo: UnsafeMutableRawPointer ? ,
443512 callback: FMLanguageModelSessionStructuredResponseCallback
444513) -> FMTaskRef {
445514 let session = Unmanaged < LanguageModelSession > . fromOpaque ( session) . takeUnretainedValue ( )
446515 let promptString = String ( cString: prompt)
447516 let schemaBuilder = Unmanaged < GenerationSchemaBuilder > . fromOpaque ( schema) . takeUnretainedValue ( )
517+ let optionsJSONString = optionsJSON. map ( String . init ( cString: ) )
448518 let unsafeSendableUserInfo = UnsafeSendableUserInfo ( pointer: userInfo)
449519
450520 let task = Task . detached {
@@ -455,9 +525,16 @@ public func FMLanguageModelSessionRespondWithSchema(
455525 // Build the final schema from the builder
456526 let finalSchema = try schemaBuilder. buildSchema ( )
457527
528+ // Parse options if provided
529+ let options = try parseGenerationOptions ( from: optionsJSONString)
530+
458531 // Use Foundation Models guided generation API
459532 try Task . checkCancellation ( )
460- let response = try await session. respond ( to: promptString, schema: finalSchema)
533+ let response = try await session. respond (
534+ to: promptString,
535+ schema: finalSchema,
536+ options: options ?? GenerationOptions ( )
537+ )
461538
462539 // Check cancellation before callback
463540 try Task . checkCancellation ( )
@@ -502,12 +579,14 @@ public func FMLanguageModelSessionRespondWithSchemaFromJSON(
502579 session: FMLanguageModelSessionRef ,
503580 prompt: UnsafePointer < CChar > ,
504581 jsonSchema: UnsafePointer < CChar > ,
582+ optionsJSON: UnsafePointer < CChar > ? ,
505583 userInfo: UnsafeMutableRawPointer ? ,
506584 callback: FMLanguageModelSessionStructuredResponseCallback
507585) -> FMTaskRef {
508586 let session = Unmanaged < LanguageModelSession > . fromOpaque ( session) . takeUnretainedValue ( )
509587 let promptString = String ( cString: prompt)
510588 let jsonSchemaString = String ( cString: jsonSchema)
589+ let optionsJSONString = optionsJSON. map ( String . init ( cString: ) )
511590 let unsafeSendableUserInfo = UnsafeSendableUserInfo ( pointer: userInfo)
512591
513592 let task = Task . detached {
@@ -521,8 +600,15 @@ public func FMLanguageModelSessionRespondWithSchemaFromJSON(
521600 from: Data ( jsonSchemaString. utf8)
522601 )
523602
603+ // Parse options if provided
604+ let options = try parseGenerationOptions ( from: optionsJSONString)
605+
524606 try Task . checkCancellation ( )
525- let response = try await session. respond ( to: promptString, schema: schema)
607+ let response = try await session. respond (
608+ to: promptString,
609+ schema: schema,
610+ options: options ?? GenerationOptions ( )
611+ )
526612
527613 // Check cancellation before callback
528614 try Task . checkCancellation ( )
0 commit comments