@xybrid/react-native 0.10.1 → 0.13.0

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 CHANGED
@@ -215,8 +215,9 @@ const download = await loader.download();
215
215
  for await (const status of download!.progress()) setProgress(status.progress);
216
216
  const model = await loader.load();
217
217
 
218
- // Answer from the cloud while the weights download (needs an API key).
219
- const fast = await ModelLoader.fromRegistrySpeculative('qwen3.5-0.8b').load();
218
+ // Answer from the cloud while the weights download (needs an API key and a
219
+ // chat model the registry serves as a direct GGUF download).
220
+ const fast = await ModelLoader.fromRegistrySpeculative('lfm2.5-350m').load();
220
221
  await fast.isCloudServing(); // true until the local weights land
221
222
 
222
223
  await Xybrid.modelCacheStatus(); // bytes and models on disk
@@ -57,5 +57,5 @@ dependencies {
57
57
 
58
58
  // The Kotlin SDK. Kept in lockstep with the workspace version by
59
59
  // tools/scripts/version-sync.sh (`just bump-version`).
60
- implementation "ai.xybrid:xybrid-kotlin:0.10.1"
60
+ implementation "ai.xybrid:xybrid-kotlin:0.13.0"
61
61
  }
@@ -429,9 +429,12 @@ class XybridModule(reactContext: ReactApplicationContext) : NativeXybridSpec(rea
429
429
  handles.dispose(stream)
430
430
  mapOf("kind" to "complete", "result" to XybridCodec.encodeResult(result))
431
431
  }
432
+ XybridStreamEventKind.AUDIO -> throw BridgeException.InvalidArgument(
433
+ "Token streams cannot deliver audio; use run for batch speech"
434
+ )
432
435
  }
433
436
  } catch (t: Throwable) {
434
- // A failed pull already closed the bolt session.
437
+ // Dispose also aborts a stream rejected for an unsupported event.
435
438
  handles.dispose(stream)
436
439
  throw cancellationAware(t, s.cancel)
437
440
  }
@@ -616,9 +616,11 @@ public final class XybridModuleImpl: NSObject {
616
616
  let result = try entry.model.streamResult(streamId: entry.streamId)
617
617
  handles.dispose(stream)
618
618
  return ["kind": "complete", "result": XybridCodec.encodeResult(result)] as JSObject
619
+ case .audio:
620
+ throw BridgeError.invalidArgument("Token streams cannot deliver audio; use run for batch speech")
619
621
  }
620
622
  } catch {
621
- // A failed pull already closed the bolt session.
623
+ // Dispose also aborts a stream rejected for an unsupported event.
622
624
  handles.dispose(stream)
623
625
  throw Self.cancellationAware(error, entry.cancel)
624
626
  }
@@ -162,8 +162,9 @@ public enum Xybrid {
162
162
  /// ``ModelLoader/fromRegistrySpeculative(_:)`` opts in explicitly and is
163
163
  /// unaffected by this toggle. Off by default. Either way, speculation also
164
164
  /// needs a resolvable API key and a model that is not already cached —
165
- /// ``ModelLoader/willSpeculate`` reports the combined answer for a
166
- /// specific loader.
165
+ /// ``ModelLoader/willSpeculate`` checks both for a specific loader — and
166
+ /// the load asks the registry first, so only chat models are served this
167
+ /// way.
167
168
  public static func setSpeculativeCloud(_ enabled: Bool) {
168
169
  boltSetSpeculativeCloud(enabled)
169
170
  }
@@ -366,9 +367,10 @@ public struct ModelLoader: Sendable {
366
367
  ///
367
368
  /// ``load()`` returns almost immediately with a cloud-backed model that
368
369
  /// switches to on-device by itself once the download lands. Requires an API
369
- /// key and an uncached model — otherwise it behaves exactly like
370
- /// ``fromRegistry(_:)``, which ``willSpeculate`` reports up front. LLM/chat
371
- /// models only.
370
+ /// key, an uncached model, and a chat model the registry serves as a direct
371
+ /// download (GGUF or vision-language, not a `.xyb` bundle) — otherwise it
372
+ /// behaves exactly like ``fromRegistry(_:)``. ``willSpeculate`` checks the
373
+ /// first two up front.
372
374
  ///
373
375
  /// Track the handover with ``XybridModel/isCloudServing()``,
374
376
  /// ``XybridModel/downloadStatus()`` and ``XybridModel/awaitDownload(timeoutMs:)``.
@@ -376,10 +378,13 @@ public struct ModelLoader: Sendable {
376
378
  Self(source: .registrySpeculative(id))
377
379
  }
378
380
 
379
- /// Whether ``load()`` would actually speculate: speculation is possible for
380
- /// this source, an API key resolves, and the model is not already cached.
381
+ /// Whether ``load()`` may speculate: speculation is possible for this
382
+ /// source, an API key resolves, and the model is not already cached.
381
383
  ///
382
- /// Always `false` for non-speculative sources. Never touches the network.
384
+ /// Always `false` for non-speculative sources. Never touches the network,
385
+ /// so it cannot know the model type: ``load()`` asks the registry and
386
+ /// speculates only for a chat model. ``XybridModel/isCloudServing()``
387
+ /// reports the outcome.
383
388
  public var willSpeculate: Bool {
384
389
  guard case .registrySpeculative(let id) = source else { return false }
385
390
  return willSpeculateForModel(modelId: id)
@@ -643,6 +648,11 @@ private final class XybridTokenStreamState: @unchecked Sendable {
643
648
  case .complete:
644
649
  close()
645
650
  return nil
651
+ case .audio:
652
+ close()
653
+ throw XybridError.inferenceError(
654
+ message: "Token streams cannot deliver audio; use run for batch speech"
655
+ )
646
656
  }
647
657
  }
648
658
 
@@ -592,6 +592,42 @@ public struct XybridStreamToken: Hashable, Equatable, Sendable {
592
592
  }
593
593
  }
594
594
 
595
+ /// Owned PCM16 LE packet. Offsets count samples per channel.
596
+ public struct XybridTtsAudioChunk: Hashable, Equatable, Sendable {
597
+ public var pcm: Data
598
+ public var sampleRate: UInt32
599
+ public var channels: UInt32
600
+ public var firstSample: UInt64
601
+
602
+ public init(
603
+ pcm: Data,
604
+ sampleRate: UInt32,
605
+ channels: UInt32,
606
+ firstSample: UInt64
607
+ ) {
608
+ self.pcm = pcm
609
+ self.sampleRate = sampleRate
610
+ self.channels = channels
611
+ self.firstSample = firstSample
612
+ }
613
+
614
+ @inlinable static func decode(from reader: inout WireReader) -> XybridTtsAudioChunk {
615
+ XybridTtsAudioChunk(
616
+ pcm: reader.readBytes(),
617
+ sampleRate: reader.readU32(),
618
+ channels: reader.readU32(),
619
+ firstSample: reader.readU64()
620
+ )
621
+ }
622
+
623
+ @inlinable func encode(to writer: inout WireWriter) {
624
+ writer.writeBytes(self.pcm)
625
+ writer.writeU32(self.sampleRate)
626
+ writer.writeU32(self.channels)
627
+ writer.writeU64(self.firstSample)
628
+ }
629
+ }
630
+
595
631
  /// One pull from a streaming inference session.
596
632
  ///
597
633
  /// This is a flat record instead of a data-carrying enum because the pinned
@@ -603,19 +639,22 @@ public struct XybridStreamToken: Hashable, Equatable, Sendable {
603
639
  public struct XybridStreamEvent: Hashable, Equatable, Sendable {
604
640
  public var kind: XybridStreamEventKind
605
641
  public var token: XybridStreamToken?
642
+ public var audio: XybridTtsAudioChunk?
606
643
 
607
- public init(kind: XybridStreamEventKind, token: XybridStreamToken?) {
644
+ public init(kind: XybridStreamEventKind, token: XybridStreamToken?, audio: XybridTtsAudioChunk?) {
608
645
  self.kind = kind
609
646
  self.token = token
647
+ self.audio = audio
610
648
  }
611
649
 
612
650
  @inlinable static func decode(from reader: inout WireReader) -> XybridStreamEvent {
613
- XybridStreamEvent(kind: XybridStreamEventKind(rawValue: reader.readI32())!, token: reader.readOptional { reader in XybridStreamToken.decode(from: &reader) })
651
+ XybridStreamEvent(kind: XybridStreamEventKind(rawValue: reader.readI32())!, token: reader.readOptional { reader in XybridStreamToken.decode(from: &reader) }, audio: reader.readOptional { reader in XybridTtsAudioChunk.decode(from: &reader) })
614
652
  }
615
653
 
616
654
  @inlinable func encode(to writer: inout WireWriter) {
617
655
  writer.writeI32(self.kind.rawValue)
618
656
  writer.writeOptional(self.token) { writer, boltffiValue0 in boltffiValue0.encode(to: &writer) }
657
+ writer.writeOptional(self.audio) { writer, boltffiValue0 in boltffiValue0.encode(to: &writer) }
619
658
  }
620
659
  }
621
660
 
@@ -1122,6 +1161,7 @@ public enum XybridDownloadState: Int32, Hashable, Sendable, CaseIterable {
1122
1161
  public enum XybridStreamEventKind: Int32, Hashable, Sendable, CaseIterable {
1123
1162
  case token = 0
1124
1163
  case complete = 1
1164
+ case audio = 2
1125
1165
 
1126
1166
  @usableFromInline init(fromC c: Int32) {
1127
1167
  self = XybridStreamEventKind(rawValue: c)!
@@ -1414,9 +1454,11 @@ public final class XybridModel {
1414
1454
  /// download in the background.
1415
1455
  ///
1416
1456
  /// Returns almost immediately instead of blocking on the download. Requires
1417
- /// a resolvable API key and an uncached model; otherwise it behaves exactly
1418
- /// like `from_registry`. Poll `download_status` for progress and
1419
- /// `is_cloud_serving` to know which leg is answering. LLM/chat models only.
1457
+ /// a resolvable API key, an uncached model, and a chat model the registry
1458
+ /// serves as a direct download (GGUF or vision-language, not a `.xyb`
1459
+ /// bundle); otherwise it behaves exactly like `from_registry`. Poll
1460
+ /// `download_status` for progress and `is_cloud_serving` to know which leg
1461
+ /// is answering.
1420
1462
  public init(fromRegistrySpeculative id: String) throws {
1421
1463
  let boltffiIdBytes = boltffiEncode { boltffiIdWriter in boltffiIdWriter.writeString(id) }
1422
1464
  let boltffiHandle = try boltffiIdBytes.withUnsafeBufferPointer { boltffiIdBuffer in
@@ -2428,11 +2470,12 @@ public func setPlatformUrl(url: String) {
2428
2470
  }
2429
2471
  }
2430
2472
 
2431
- /// Enable speculative cloud fallback globally: a registry model that isn't
2432
- /// downloaded yet is served from the gateway while the weights download.
2473
+ /// Enable speculative cloud fallback globally: a registry chat model that
2474
+ /// isn't downloaded yet is served from the gateway while the weights download.
2433
2475
  ///
2434
- /// LLM/chat only — prefer `XybridModel.fromRegistrySpeculative` when the app
2435
- /// also loads ASR/TTS models, which cannot be served this way.
2476
+ /// An uncached load asks the registry first, so other models (ASR, TTS,
2477
+ /// `.xyb` bundles) download and load as usual.
2478
+ /// `XybridModel.fromRegistrySpeculative` opts a single load in instead.
2436
2479
  public func setSpeculativeCloud(enabled: Bool) {
2437
2480
  boltffi_function_xybrid_bolt_set_speculative_cloud(enabled)
2438
2481
  }
@@ -2447,11 +2490,13 @@ public func isSpeculativeCloudEnabled() -> Bool {
2447
2490
  return boltffi_function_xybrid_bolt_is_speculative_cloud_enabled()
2448
2491
  }
2449
2492
 
2450
- /// Whether `XybridModel::from_registry_speculative(model_id)` would actually
2451
- /// speculate: an API key resolves and the model is not already cached.
2493
+ /// Whether `XybridModel::from_registry_speculative(model_id)` may speculate:
2494
+ /// an API key resolves and the model is not already cached.
2452
2495
  ///
2453
- /// Lets the hand-written Swift/Kotlin loader facades answer "will this
2454
- /// speculate?" before loading. Never touches the network.
2496
+ /// Lets the hand-written Swift/Kotlin loader facades answer "can this
2497
+ /// speculate?" before loading. Never touches the network, so it cannot know
2498
+ /// the model type: the load asks the registry and speculates only for a chat
2499
+ /// model.
2455
2500
  public func willSpeculateForModel(modelId: String) -> Bool {
2456
2501
  let boltffiModelIdBytes = boltffiEncode { boltffiModelIdWriter in boltffiModelIdWriter.writeString(modelId) }
2457
2502
  return boltffiModelIdBytes.withUnsafeBufferPointer { boltffiModelIdBuffer in
@@ -45,8 +45,10 @@ class ModelLoader {
45
45
  * Serve from the cloud gateway while the registry weights download in the
46
46
  * background, instead of blocking on the download. `load()` then resolves
47
47
  * almost immediately with a model that switches to on-device by itself.
48
- * Needs an API key and an uncached model — {@link willSpeculate} tells you
49
- * up front — otherwise it behaves like {@link fromRegistry}. LLM/chat only.
48
+ * Needs an API key, an uncached model ({@link willSpeculate} checks both up
49
+ * front) and a chat model the registry serves as a direct download (GGUF or
50
+ * vision-language, not a `.xyb` bundle) — otherwise it behaves like
51
+ * {@link fromRegistry}.
50
52
  */
51
53
  static fromRegistrySpeculative(id) {
52
54
  return new ModelLoader({ kind: 'registrySpeculative', id });
@@ -72,8 +74,10 @@ class ModelLoader {
72
74
  return new Model(await NativeXybrid_1.default.loadModel(toWireSource(this.source)));
73
75
  }
74
76
  /**
75
- * Whether {@link load} would actually speculate: a speculative source, an
76
- * API key, and a model not yet cached. Never touches the network.
77
+ * Whether {@link load} may speculate: a speculative source, an API key, and
78
+ * a model not yet cached. Never touches the network, so it cannot know the
79
+ * model type: `load()` asks the registry and speculates only for a chat
80
+ * model. `isCloudServing()` on the loaded model reports the outcome.
77
81
  */
78
82
  async willSpeculate() {
79
83
  if (this.source.kind !== 'registrySpeculative')
@@ -50,9 +50,9 @@ exports.Xybrid = {
50
50
  },
51
51
  /**
52
52
  * Default speculative cloud serving on or off for loads that don't opt in
53
- * per load (`ModelLoader.fromRegistrySpeculative` always speculates). Needs
54
- * an API key. LLM/chat only — prefer the per-load form when the app also
55
- * loads ASR/TTS models.
53
+ * per load (`ModelLoader.fromRegistrySpeculative` opts in itself). Needs an
54
+ * API key. An uncached load asks the registry first, so only chat models
55
+ * are served this way; ASR, TTS and `.xyb` bundles load as usual.
56
56
  */
57
57
  setSpeculativeCloud(enabled) {
58
58
  return NativeXybrid_1.default.setSpeculativeCloud(enabled);
@@ -39,8 +39,10 @@ export class ModelLoader {
39
39
  * Serve from the cloud gateway while the registry weights download in the
40
40
  * background, instead of blocking on the download. `load()` then resolves
41
41
  * almost immediately with a model that switches to on-device by itself.
42
- * Needs an API key and an uncached model — {@link willSpeculate} tells you
43
- * up front — otherwise it behaves like {@link fromRegistry}. LLM/chat only.
42
+ * Needs an API key, an uncached model ({@link willSpeculate} checks both up
43
+ * front) and a chat model the registry serves as a direct download (GGUF or
44
+ * vision-language, not a `.xyb` bundle) — otherwise it behaves like
45
+ * {@link fromRegistry}.
44
46
  */
45
47
  static fromRegistrySpeculative(id) {
46
48
  return new ModelLoader({ kind: 'registrySpeculative', id });
@@ -66,8 +68,10 @@ export class ModelLoader {
66
68
  return new Model(await NativeXybrid.loadModel(toWireSource(this.source)));
67
69
  }
68
70
  /**
69
- * Whether {@link load} would actually speculate: a speculative source, an
70
- * API key, and a model not yet cached. Never touches the network.
71
+ * Whether {@link load} may speculate: a speculative source, an API key, and
72
+ * a model not yet cached. Never touches the network, so it cannot know the
73
+ * model type: `load()` asks the registry and speculates only for a chat
74
+ * model. `isCloudServing()` on the loaded model reports the outcome.
71
75
  */
72
76
  async willSpeculate() {
73
77
  if (this.source.kind !== 'registrySpeculative')
@@ -44,9 +44,9 @@ export const Xybrid = {
44
44
  },
45
45
  /**
46
46
  * Default speculative cloud serving on or off for loads that don't opt in
47
- * per load (`ModelLoader.fromRegistrySpeculative` always speculates). Needs
48
- * an API key. LLM/chat only — prefer the per-load form when the app also
49
- * loads ASR/TTS models.
47
+ * per load (`ModelLoader.fromRegistrySpeculative` opts in itself). Needs an
48
+ * API key. An uncached load asks the registry first, so only chat models
49
+ * are served this way; ASR, TTS and `.xyb` bundles load as usual.
50
50
  */
51
51
  setSpeculativeCloud(enabled) {
52
52
  return NativeXybrid.setSpeculativeCloud(enabled);
@@ -66,8 +66,10 @@ export declare class ModelLoader {
66
66
  * Serve from the cloud gateway while the registry weights download in the
67
67
  * background, instead of blocking on the download. `load()` then resolves
68
68
  * almost immediately with a model that switches to on-device by itself.
69
- * Needs an API key and an uncached model — {@link willSpeculate} tells you
70
- * up front — otherwise it behaves like {@link fromRegistry}. LLM/chat only.
69
+ * Needs an API key, an uncached model ({@link willSpeculate} checks both up
70
+ * front) and a chat model the registry serves as a direct download (GGUF or
71
+ * vision-language, not a `.xyb` bundle) — otherwise it behaves like
72
+ * {@link fromRegistry}.
71
73
  */
72
74
  static fromRegistrySpeculative(id: string): ModelLoader;
73
75
  /** A local `.xyb` bundle. */
@@ -83,8 +85,10 @@ export declare class ModelLoader {
83
85
  /** Resolve, download if needed, and load. Rejects with a typed `xybrid_*` code. */
84
86
  load(): Promise<Model>;
85
87
  /**
86
- * Whether {@link load} would actually speculate: a speculative source, an
87
- * API key, and a model not yet cached. Never touches the network.
88
+ * Whether {@link load} may speculate: a speculative source, an API key, and
89
+ * a model not yet cached. Never touches the network, so it cannot know the
90
+ * model type: `load()` asks the registry and speculates only for a chat
91
+ * model. `isCloudServing()` on the loaded model reports the outcome.
88
92
  */
89
93
  willSpeculate(): Promise<boolean>;
90
94
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/model.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,WAAW,EACX,eAAe,EACf,SAAS,EACV,MAAM,SAAS,CAAC;AAYjB;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,sDAAsD;IACtD,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,kFAAkF;AAClF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAoBxC;;;GAGG;AACH,qBAAa,WAAW;IACF,QAAQ,CAAC,MAAM,EAAE,WAAW;IAAhD,OAAO;IAEP,2BAA2B;IAC3B,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW;IAI7C,8DAA8D;IAC9D,MAAM,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW;IAI5C;;;;;;OAMG;IACH,MAAM,CAAC,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW;IAIvD,6BAA6B;IAC7B,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAI5C,0DAA0D;IAC1D,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAI/C,uFAAuF;IACvF,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,WAAW;IAItF,gFAAgF;IAChF,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAI/C,mFAAmF;IAC7E,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;IAI5B;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAKvC;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;CAKnF;AAED,+EAA+E;AAC/E,qBAAa,KAAK;IAGd,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM;IAHzB,8CAA8C;;IAE5C,iEAAiE;IACxD,MAAM,EAAE,MAAM;IAGzB,qDAAqD;IAC/C,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC;IAWhC,wFAAwF;IACxF,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B;;;OAGG;IACG,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAejF;;;;;;;;;;;;;;;;;OAiBG;IACI,YAAY,CACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,UAAe,GACvB,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,SAAS,EAAE,IAAI,CAAC;IAiCjE;;;;OAIG;IACG,MAAM,CAAC,MAAM,GAAE,eAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAIrE,iFAAiF;IACjF,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;OAGG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAIlC,gFAAgF;IAC1E,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC;IAM/C;;;OAGG;IACH,gBAAgB,CAAC,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,cAAc,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC;IAInG;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAM/D,mDAAmD;IAC7C,MAAM,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIpC,sDAAsD;IAChD,YAAY,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAI/C,2BAA2B;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAIvD;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzB;AA+BD;;;;GAIG;AACH,qBAAa,aAAa;IAEZ,QAAQ,CAAC,MAAM,EAAE,MAAM;IADnC,gBAAgB;gBACK,MAAM,EAAE,MAAM;IAEnC,wDAAwD;IAClD,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAMvC,iEAAiE;IACjE,KAAK,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI/B,iEAAiE;IACjE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,cAAc,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC;IAI3F,mEAAmE;IACnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzB"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/model.ts"],"names":[],"mappings":"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"}
@@ -46,9 +46,9 @@ export declare const Xybrid: {
46
46
  setPlatformUrl(url: string): Promise<void>;
47
47
  /**
48
48
  * Default speculative cloud serving on or off for loads that don't opt in
49
- * per load (`ModelLoader.fromRegistrySpeculative` always speculates). Needs
50
- * an API key. LLM/chat only — prefer the per-load form when the app also
51
- * loads ASR/TTS models.
49
+ * per load (`ModelLoader.fromRegistrySpeculative` opts in itself). Needs an
50
+ * API key. An uncached load asks the registry first, so only chat models
51
+ * are served this way; ASR, TTS and `.xyb` bundles load as usual.
52
52
  */
53
53
  setSpeculativeCloud(enabled: boolean): Promise<void>;
54
54
  isSpeculativeCloudEnabled(): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xybrid/react-native",
3
- "version": "0.10.1",
3
+ "version": "0.13.0",
4
4
  "description": "On-device (and optionally cloud) ML inference for React Native: LLM, ASR, TTS, embeddings and vision, backed by the Xybrid Rust SDK",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -70,7 +70,7 @@
70
70
  "typescript": "^5.9.3"
71
71
  },
72
72
  "xybrid": {
73
- "iosXcframeworkSha256": "3b012f6be628845d86ef274824de7b1e8c23c1b551b6965d18efd98268ee8b14"
73
+ "iosXcframeworkSha256": "a3a6abdadeea791a4fcc3fc005746b9115fced514725a0faf657774a22652ad9"
74
74
  },
75
75
  "codegenConfig": {
76
76
  "name": "RNXybridSpec",
package/src/model.ts CHANGED
@@ -101,8 +101,10 @@ export class ModelLoader {
101
101
  * Serve from the cloud gateway while the registry weights download in the
102
102
  * background, instead of blocking on the download. `load()` then resolves
103
103
  * almost immediately with a model that switches to on-device by itself.
104
- * Needs an API key and an uncached model — {@link willSpeculate} tells you
105
- * up front — otherwise it behaves like {@link fromRegistry}. LLM/chat only.
104
+ * Needs an API key, an uncached model ({@link willSpeculate} checks both up
105
+ * front) and a chat model the registry serves as a direct download (GGUF or
106
+ * vision-language, not a `.xyb` bundle) — otherwise it behaves like
107
+ * {@link fromRegistry}.
106
108
  */
107
109
  static fromRegistrySpeculative(id: string): ModelLoader {
108
110
  return new ModelLoader({ kind: 'registrySpeculative', id });
@@ -134,8 +136,10 @@ export class ModelLoader {
134
136
  }
135
137
 
136
138
  /**
137
- * Whether {@link load} would actually speculate: a speculative source, an
138
- * API key, and a model not yet cached. Never touches the network.
139
+ * Whether {@link load} may speculate: a speculative source, an API key, and
140
+ * a model not yet cached. Never touches the network, so it cannot know the
141
+ * model type: `load()` asks the registry and speculates only for a chat
142
+ * model. `isCloudServing()` on the loaded model reports the outcome.
139
143
  */
140
144
  async willSpeculate(): Promise<boolean> {
141
145
  if (this.source.kind !== 'registrySpeculative') return false;
package/src/xybrid.ts CHANGED
@@ -75,9 +75,9 @@ export const Xybrid = {
75
75
 
76
76
  /**
77
77
  * Default speculative cloud serving on or off for loads that don't opt in
78
- * per load (`ModelLoader.fromRegistrySpeculative` always speculates). Needs
79
- * an API key. LLM/chat only — prefer the per-load form when the app also
80
- * loads ASR/TTS models.
78
+ * per load (`ModelLoader.fromRegistrySpeculative` opts in itself). Needs an
79
+ * API key. An uncached load asks the registry first, so only chat models
80
+ * are served this way; ASR, TTS and `.xyb` bundles load as usual.
81
81
  */
82
82
  setSpeculativeCloud(enabled: boolean): Promise<void> {
83
83
  return NativeXybrid.setSpeculativeCloud(enabled);