expo-local-llm 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/ios/ExpoLocalLlmModule.swift +0 -2
- package/ios/FoundationModelBridge.swift +2 -1
- package/ios/LLMSession.swift +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,6 +163,28 @@ const recipe = JSON.parse(await respond('Give me a pasta recipe'));
|
|
|
163
163
|
- Tool calling is iOS 26+ only. Android will throw at session creation if tools are passed.
|
|
164
164
|
- Structured output uses instruction-based JSON guidance, not Apple's constrained decoding.
|
|
165
165
|
|
|
166
|
+
## Why an Expo module?
|
|
167
|
+
|
|
168
|
+
This is built as an [Expo Module](https://docs.expo.dev/modules/overview/), not
|
|
169
|
+
a bare React Native library. Here's why:
|
|
170
|
+
|
|
171
|
+
- **`expo install` and go** — no manual Xcode/Gradle linking, no `pod install`
|
|
172
|
+
surprises. Works with `npx expo prebuild` and managed workflow out of the box.
|
|
173
|
+
- **SharedObject lifecycle** — `LLMSession` extends Expo's `SharedObject`, which
|
|
174
|
+
handles native memory management, event subscriptions, and cleanup
|
|
175
|
+
automatically when the JS object is garbage collected. In bare RN you'd wire
|
|
176
|
+
this yourself with `NativeEventEmitter` and manual release calls.
|
|
177
|
+
- **Class DSL** — the native module exposes `LLMSession` as a first-class JS
|
|
178
|
+
object with instance methods (`session.respond()`, `session.streamResponse()`)
|
|
179
|
+
rather than flat module-level functions with session IDs. This is an Expo
|
|
180
|
+
Modules API feature that doesn't exist in the classic RN bridge.
|
|
181
|
+
- **Cross-platform parity** — Expo's Kotlin DSL mirrors the Swift DSL, so the
|
|
182
|
+
iOS and Android modules have the same structure. Adding Android tool calling
|
|
183
|
+
later means implementing the same interface, not building a separate bridge.
|
|
184
|
+
|
|
185
|
+
If you're on bare React Native without Expo, this module won't work — you'd need
|
|
186
|
+
to add `expo-modules-core` as a dependency or use a different library.
|
|
187
|
+
|
|
166
188
|
## How is this different from @callstack/ai? (as of March 2026)
|
|
167
189
|
|
|
168
190
|
[@callstack/ai](https://github.com/callstackincubator/ai) is a full-featured
|
|
@@ -52,8 +52,6 @@ public class ExpoLocalLlmModule: Module {
|
|
|
52
52
|
Function("rejectToolCall") { (session: LLMSession, callId: String, error: String) in
|
|
53
53
|
try session.rejectToolCall(callId: callId, error: error)
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
Events("token", "streamComplete", "streamError", "toolCall")
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
OnAppEntersForeground {
|
|
@@ -23,7 +23,8 @@ enum FoundationModelBridge {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
static func createSession(instructions: String?,
|
|
26
|
+
static func createSession(instructions: String?, dynamicTools: [DynamicTool] = []) -> LanguageModelSession {
|
|
27
|
+
let tools: [any Tool] = dynamicTools
|
|
27
28
|
if tools.isEmpty {
|
|
28
29
|
if let instructions {
|
|
29
30
|
return LanguageModelSession(instructions: instructions)
|
package/ios/LLMSession.swift
CHANGED
|
@@ -113,7 +113,7 @@ class LLMSession: SharedObject {
|
|
|
113
113
|
// Cancel any pending tool calls from the old session
|
|
114
114
|
store.cancelAll()
|
|
115
115
|
|
|
116
|
-
var
|
|
116
|
+
var dynamicTools: [DynamicTool] = []
|
|
117
117
|
registeredTools.removeAll()
|
|
118
118
|
|
|
119
119
|
for config in toolConfigs {
|
|
@@ -138,12 +138,12 @@ class LLMSession: SharedObject {
|
|
|
138
138
|
])
|
|
139
139
|
}
|
|
140
140
|
registeredTools[config.name] = tool
|
|
141
|
-
|
|
141
|
+
dynamicTools.append(tool)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
nativeSession = FoundationModelBridge.createSession(
|
|
145
145
|
instructions: sessionInstructions,
|
|
146
|
-
|
|
146
|
+
dynamicTools: dynamicTools
|
|
147
147
|
)
|
|
148
148
|
}
|
|
149
149
|
|
package/package.json
CHANGED