Summary
While integrating llama_cpp_dart (feat/0.9.0-architecture) into a production iOS app with MediaPipe Gemma + GGUF model switching, several gaps in the public API surfaced that caused crashes and required complex workarounds on the app side. These improvements would make the library significantly safer and more ergonomic for mobile callers.
1. ContextParams.mobile() factory constructor
Problem: Default ContextParams values (nCtx: 4096, nBatch: 2048, nUbatch: 512) are desktop-tuned. Any iOS caller that forgets to override them gets BLAS operator new heap OOM crashes via Apple Accelerate (ggml_backend_blas_graph_compute), which iOS Jetsam kills silently with no stack trace in the app. This is a silent footgun.
Proposed fix:
/// Memory-safe defaults for iOS/Android mobile devices.
/// nCtx=1024, nBatch=128, nUbatch=128, KV cache quantized to q8_0.
factory ContextParams.mobile() => const ContextParams(
nCtx: 1024,
nBatch: 128,
nUbatch: 128,
typeK: KvCacheType.q8_0,
typeV: KvCacheType.q8_0,
);
2. LlamaEngine.estimateMemoryBytes() pre-flight check
Problem: ModelParams.noAlloc exists and simulates load without allocating tensors — but this capability is not exposed as a public workflow. Mobile apps need to check required RAM before committing to load a model, especially since iOS Jetsam kills silently with no OOM signal.
Proposed fix:
/// Loads model metadata only (noAlloc: true) and returns estimated
/// peak memory bytes required for the given context params.
/// Throws if the model file doesn't exist or is unreadable.
static Future<int> estimateMemoryBytes({
required ModelParams modelParams,
required ContextParams contextParams,
}) async { ... }
This lets mobile apps gate downloads/loads: if (estimate > availableRAM) showWarning().
3. LlamaEngine.isDisposed public getter
Problem: _disposed is private. Callers have no way to check engine liveness before calling createChat(), which throws LlamaLibraryException('LlamaEngine has been disposed.'). This forces callers to maintain their own shadow state tracking.
Proposed fix:
/// True if [dispose] has been called. Subsequent [createChat] calls will throw.
bool get isDisposed => _disposed;
4. EngineChat.cancel() shorthand
Problem: Stopping generation requires the caller to hold and cancel the Dart StreamSubscription — not obvious from the API surface and error-prone (callers may forget to cancel and leak the stream). StopUserAbort exists in the type system but isn't surfaced as a first-class operation.
Proposed fix:
/// Cancels the active generation stream, emitting [StopUserAbort].
/// Safe to call when no generation is in progress (no-op).
Future<void> cancel() async { ... }
5. iOS Metal verification — document LlamaEngine.devices usage
Problem: LlamaEngine.devices, hasAccelerator, and primaryAcceleratorName exist but there is no documented pattern for verifying Metal is actually loaded vs silently falling back to CPU BLAS. On iOS, CPU-only BLAS is 10–20× slower than Metal and will OOM on larger models.
Proposed docs addition:
// After spawn, verify Metal is active:
final engine = await LlamaEngine.spawnFromProcess(...);
if (engine.primaryAcceleratorName != 'Metal') {
// warn user: running on CPU only — expect slow inference + higher OOM risk
}
Context
Summary
While integrating
llama_cpp_dart(feat/0.9.0-architecture) into a production iOS app with MediaPipe Gemma + GGUF model switching, several gaps in the public API surfaced that caused crashes and required complex workarounds on the app side. These improvements would make the library significantly safer and more ergonomic for mobile callers.1.
ContextParams.mobile()factory constructorProblem: Default
ContextParamsvalues (nCtx: 4096,nBatch: 2048,nUbatch: 512) are desktop-tuned. Any iOS caller that forgets to override them gets BLASoperator newheap OOM crashes via Apple Accelerate (ggml_backend_blas_graph_compute), which iOS Jetsam kills silently with no stack trace in the app. This is a silent footgun.Proposed fix:
2.
LlamaEngine.estimateMemoryBytes()pre-flight checkProblem:
ModelParams.noAllocexists and simulates load without allocating tensors — but this capability is not exposed as a public workflow. Mobile apps need to check required RAM before committing to load a model, especially since iOS Jetsam kills silently with no OOM signal.Proposed fix:
This lets mobile apps gate downloads/loads:
if (estimate > availableRAM) showWarning().3.
LlamaEngine.isDisposedpublic getterProblem:
_disposedis private. Callers have no way to check engine liveness before callingcreateChat(), which throwsLlamaLibraryException('LlamaEngine has been disposed.'). This forces callers to maintain their own shadow state tracking.Proposed fix:
4.
EngineChat.cancel()shorthandProblem: Stopping generation requires the caller to hold and cancel the Dart
StreamSubscription— not obvious from the API surface and error-prone (callers may forget to cancel and leak the stream).StopUserAbortexists in the type system but isn't surfaced as a first-class operation.Proposed fix:
5. iOS Metal verification — document
LlamaEngine.devicesusageProblem:
LlamaEngine.devices,hasAccelerator, andprimaryAcceleratorNameexist but there is no documented pattern for verifying Metal is actually loaded vs silently falling back to CPU BLAS. On iOS, CPU-only BLAS is 10–20× slower than Metal and will OOM on larger models.Proposed docs addition:
Context