1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! Rust bindings for Apple's FoundationModels.framework
//!
//! This crate provides safe, idiomatic Rust bindings to Apple's `FoundationModels` framework,
//! which enables on-device AI capabilities powered by Apple Intelligence.
//!
//! # Platform Requirements
//!
//! - **Minimum OS**: macOS 26.0+ or iOS/iPadOS 26.0+
//! - **Apple Intelligence**: Must be enabled on the device
//! - **Device**: Apple Silicon / Apple Intelligence-capable device
//!
//! # Quick Start
//!
//! ```rust,no_run
//! use fm_rs::{SystemLanguageModel, Session, GenerationOptions};
//!
//! // Create the default system language model
//! let model = SystemLanguageModel::new()?;
//!
//! // Check availability
//! if !model.is_available() {
//! println!("FoundationModels is not available on this device");
//! return Ok(());
//! }
//!
//! // Create a session with instructions
//! let session = Session::with_instructions(&model, "You are a helpful assistant.")?;
//!
//! // Send a prompt
//! let options = GenerationOptions::builder()
//! .temperature(0.7)
//! .build();
//! let response = session.respond("What is the capital of France?", &options)?;
//!
//! println!("Response: {}", response.content());
//! # Ok::<(), fm_rs::Error>(())
//! ```
//!
//! # Streaming Responses
//!
//! ```rust,no_run
//! use fm_rs::{SystemLanguageModel, Session, GenerationOptions};
//!
//! let model = SystemLanguageModel::new()?;
//! let session = Session::new(&model)?;
//!
//! session.stream_response("Tell me a story", &GenerationOptions::default(), |chunk| {
//! print!("{}", chunk);
//! })?;
//! # Ok::<(), fm_rs::Error>(())
//! ```
//!
//! # Tool Calling
//!
//! ```rust,no_run
//! use fm_rs::{SystemLanguageModel, Session, Tool, ToolOutput, GenerationOptions};
//! use serde_json::{json, Value};
//! use std::sync::Arc;
//!
//! struct WeatherTool;
//!
//! impl Tool for WeatherTool {
//! fn name(&self) -> &str { "get_weather" }
//! fn description(&self) -> &str { "Gets the current weather for a location" }
//! fn arguments_schema(&self) -> Value {
//! json!({
//! "type": "object",
//! "properties": {
//! "location": { "type": "string" }
//! },
//! "required": ["location"]
//! })
//! }
//! fn call(&self, args: Value) -> fm_rs::Result<ToolOutput> {
//! let location = args["location"].as_str().unwrap_or("Unknown");
//! Ok(ToolOutput::new(format!("Sunny, 72°F in {location}")))
//! }
//! }
//!
//! let model = SystemLanguageModel::new()?;
//! let tools: Vec<Arc<dyn Tool>> = vec![Arc::new(WeatherTool)];
//! let session = Session::with_tools(&model, &tools)?;
//!
//! let response = session.respond("What's the weather in Paris?", &GenerationOptions::default())?;
//! # Ok::<(), fm_rs::Error>(())
//! ```
//!
//! # Resource Management
//!
//! ## Session Lifecycle
//!
//! - **Ownership**: [`Session`] owns its underlying Swift `LanguageModelSession`. When
//! a `Session` is dropped, the Swift session is freed.
//! - **Thread Safety**: Both [`SystemLanguageModel`] and [`Session`] are `Send + Sync`.
//! They can be shared across threads, though concurrent calls to the same session
//! may block waiting for the model.
//! - **Drop Behavior**: Dropping a `Session` with active tool callbacks will wait
//! (up to 1 second) for in-flight callbacks to complete before freeing resources.
//!
//! ## Memory Considerations
//!
//! - Sessions maintain conversation history in memory. Long conversations can consume
//! significant memory. Use [`Session::transcript_json()`] to persist and
//! [`Session::from_transcript()`] to restore conversations.
//! - Monitor context usage with [`context_usage_from_transcript()`] and implement
//! compaction strategies using [`compact_transcript()`] when approaching limits.
//! - The default context window is approximately [`DEFAULT_CONTEXT_TOKENS`] tokens,
//! though this may vary by device and model version.
//!
//! ## Blocking Operations
//!
//! - [`Session::respond()`] blocks until generation completes. For long generations,
//! consider using [`Session::respond_with_timeout()`] or [`Session::stream_response()`].
//! - Tool callbacks are invoked synchronously during generation. Long-running tools
//! will block the generation pipeline.
//!
//! ## No Persistence Across Restarts
//!
//! Sessions do not persist across process restarts. To resume a conversation:
//! 1. Save the transcript with [`Session::transcript_json()`] before shutdown
//! 2. Restore with [`Session::from_transcript()`] on next launch
//!
//! ## Error Recovery
//!
//! - If a session enters an error state, create a new session rather than retrying.
//! - Tool errors are reported via [`Error::ToolCall`] with context about which tool
//! failed and the arguments that were passed.
/// Trait for types that can provide a JSON Schema for structured generation.
/// Re-export the derive macro when the `derive` feature is enabled.
pub use Generable;
/// Re-export `serde_json` so derive macro output doesn't require a direct dependency.
///
/// Named `__serde_json` to avoid namespace conflicts with serde's internal derive paths.
pub use serde_json as __serde_json;
// Re-export public API
pub use crate;
pub use crate;
pub use crate;
pub use crate;
pub use crate;
pub use crate;
// FFI exports for Swift to call back into Rust
/// Frees a string allocated by Rust (via `CString::into_raw`).
///
/// This function must be called by Swift to properly deallocate strings
/// returned from Rust callbacks (e.g., tool callback results).
///
/// # Safety
///
/// The pointer must have been allocated by Rust using `CString::into_raw()`.
/// Passing a pointer from any other source (e.g., Swift's strdup) is undefined behavior.
///
/// This function is called from Swift via FFI. The clippy `not_unsafe_ptr_arg_deref`
/// lint is allowed because the unsafety contract is on the FFI caller side (Swift).
pub extern "C"