@glassly/engine 0.3.8-dev.999 → 0.4.0-dev.1018

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.
Files changed (86) hide show
  1. package/build/engine.d.ts +11 -0
  2. package/build/engine.d.ts.map +1 -1
  3. package/build/facades/ai.d.ts +6 -0
  4. package/build/facades/ai.d.ts.map +1 -1
  5. package/build/facades/ai.js +6 -0
  6. package/build/facades/ai.js.map +1 -1
  7. package/build/facades/glasses.d.ts +9 -1
  8. package/build/facades/glasses.d.ts.map +1 -1
  9. package/build/facades/glasses.js +13 -0
  10. package/build/facades/glasses.js.map +1 -1
  11. package/build/generated/releaseMetadata.js +4 -4
  12. package/build/generated/releaseMetadata.js.map +1 -1
  13. package/build/index.d.ts +1 -1
  14. package/build/index.d.ts.map +1 -1
  15. package/build/index.js.map +1 -1
  16. package/build/services/CloudClientService.d.ts +2 -1
  17. package/build/services/CloudClientService.d.ts.map +1 -1
  18. package/build/services/CloudClientService.js +8 -0
  19. package/build/services/CloudClientService.js.map +1 -1
  20. package/build/services/DeviceEventRouter.d.ts.map +1 -1
  21. package/build/services/DeviceEventRouter.js +1 -0
  22. package/build/services/DeviceEventRouter.js.map +1 -1
  23. package/build/services/GlassesSensorService.js +1 -1
  24. package/build/services/GlassesSensorService.js.map +1 -1
  25. package/build/services/LlmRouting.d.ts +1 -1
  26. package/build/services/LlmRouting.js.map +1 -1
  27. package/build/services/LocalLlmModelManager.d.ts +22 -2
  28. package/build/services/LocalLlmModelManager.d.ts.map +1 -1
  29. package/build/services/LocalLlmModelManager.js +104 -2
  30. package/build/services/LocalLlmModelManager.js.map +1 -1
  31. package/build/services/LocalLlmProvider.d.ts.map +1 -1
  32. package/build/services/LocalLlmProvider.js +11 -0
  33. package/build/services/LocalLlmProvider.js.map +1 -1
  34. package/build/services/LocalMiniappRuntime.d.ts +13 -0
  35. package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
  36. package/build/services/LocalMiniappRuntime.js +61 -5
  37. package/build/services/LocalMiniappRuntime.js.map +1 -1
  38. package/build/services/NavigationHandlers.js +1 -1
  39. package/build/services/NavigationHandlers.js.map +1 -1
  40. package/build/services/NavigationService.js +6 -6
  41. package/build/services/NavigationService.js.map +1 -1
  42. package/build/services/controllers.d.ts.map +1 -1
  43. package/build/services/controllers.js +1 -0
  44. package/build/services/controllers.js.map +1 -1
  45. package/build/services/neuralBand/HandwritingGate.d.ts +38 -0
  46. package/build/services/neuralBand/HandwritingGate.d.ts.map +1 -0
  47. package/build/services/neuralBand/HandwritingGate.js +89 -0
  48. package/build/services/neuralBand/HandwritingGate.js.map +1 -0
  49. package/build/services/neuralBand/NeuralBandInput.d.ts +12 -1
  50. package/build/services/neuralBand/NeuralBandInput.d.ts.map +1 -1
  51. package/build/services/neuralBand/NeuralBandInput.js +27 -0
  52. package/build/services/neuralBand/NeuralBandInput.js.map +1 -1
  53. package/build/services/neuralBand/NeuralBandSettingsSync.d.ts.map +1 -1
  54. package/build/services/neuralBand/NeuralBandSettingsSync.js +36 -3
  55. package/build/services/neuralBand/NeuralBandSettingsSync.js.map +1 -1
  56. package/build/stores/appVisibility.d.ts.map +1 -1
  57. package/build/stores/appVisibility.js +0 -1
  58. package/build/stores/appVisibility.js.map +1 -1
  59. package/build/stores/settings.d.ts.map +1 -1
  60. package/build/stores/settings.js +18 -0
  61. package/build/stores/settings.js.map +1 -1
  62. package/build/types/enums.d.ts +2 -1
  63. package/build/types/enums.d.ts.map +1 -1
  64. package/build/types/enums.js +1 -0
  65. package/build/types/enums.js.map +1 -1
  66. package/package.json +7 -7
  67. package/src/facades/ai.ts +6 -0
  68. package/src/facades/glasses.ts +17 -0
  69. package/src/generated/releaseMetadata.ts +4 -4
  70. package/src/index.ts +1 -0
  71. package/src/services/CloudClientService.ts +8 -0
  72. package/src/services/DeviceEventRouter.ts +1 -0
  73. package/src/services/GlassesSensorService.ts +1 -1
  74. package/src/services/LlmRouting.ts +1 -1
  75. package/src/services/LocalLlmModelManager.ts +110 -3
  76. package/src/services/LocalLlmProvider.ts +8 -0
  77. package/src/services/LocalMiniappRuntime.ts +66 -5
  78. package/src/services/NavigationHandlers.ts +1 -1
  79. package/src/services/NavigationService.ts +6 -6
  80. package/src/services/controllers.ts +1 -0
  81. package/src/services/neuralBand/HandwritingGate.ts +111 -0
  82. package/src/services/neuralBand/NeuralBandInput.ts +37 -1
  83. package/src/services/neuralBand/NeuralBandSettingsSync.ts +46 -3
  84. package/src/stores/appVisibility.ts +0 -1
  85. package/src/stores/settings.ts +18 -0
  86. package/src/types/enums.ts +1 -0
@@ -291,7 +291,7 @@ function directLlmProvider(name) {
291
291
  directLlmProviders.set(name, built);
292
292
  return built;
293
293
  }
294
- const QUOTA_EXCEEDED_MESSAGE = "Monthly AI credit is used up. Upgrade in Settings > Membership, or add your own API key in Settings > API Keys.";
294
+ const QUOTA_EXCEEDED_MESSAGE = "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > API Keys.";
295
295
  /** The user's saved key (Settings > API Keys) for an LLM provider, "" if none. */
296
296
  function userLlmKey(provider) {
297
297
  const raw = useSettingsStore.getState().getSetting(MINIAPP_READABLE_API_KEYS[provider]);
@@ -459,6 +459,9 @@ class LocalMiniappRuntime {
459
459
  connectedApps = new Map();
460
460
  /** Claimed gestures (CLAIM_GESTURES): a stack per gesture, the most recent claimer holding it. */
461
461
  gestureClaims = emptyGestureClaims();
462
+ /** Apps with a text field open on the glasses (TEXT_FIELD). */
463
+ textFieldApps = new Set();
464
+ textFieldListeners = new Set();
462
465
  // The last main-view frame each app asked to render. Widget mode refuses
463
466
  // frames and demotion clears them, and an app that has drawn once may not
464
467
  // draw again on its own, so promotion replays this.
@@ -1038,6 +1041,7 @@ class LocalMiniappRuntime {
1038
1041
  }
1039
1042
  // Its gesture claims go back to whoever claimed them before.
1040
1043
  this.applyGestureClaimChanges(dropGestureClaims(this.gestureClaims, packageName));
1044
+ this.setTextFieldOpen(packageName, false);
1041
1045
  this.retainedRenders.delete(packageName);
1042
1046
  // Warm-up is a request-owned camera lease. Cancel it even if the app record was already
1043
1047
  // removed so a close racing the camera-open promise cannot leave the sensor running.
@@ -1198,6 +1202,9 @@ class LocalMiniappRuntime {
1198
1202
  case MiniappRequestType.CLAIM_GESTURES:
1199
1203
  this.handleClaimGestures(packageName, payload, requestId);
1200
1204
  break;
1205
+ case MiniappRequestType.TEXT_FIELD:
1206
+ this.handleTextField(packageName, payload, requestId);
1207
+ break;
1201
1208
  case MiniappRequestType.DISPLAY:
1202
1209
  this.handleDisplay(packageName, payload, requestId);
1203
1210
  break;
@@ -1862,6 +1869,49 @@ class LocalMiniappRuntime {
1862
1869
  this.forwardEvent(MiniappStreamType.GESTURE_CLAIM, { gesture: change.gesture, held: change.held }, undefined, change.packageName);
1863
1870
  }
1864
1871
  }
1872
+ /**
1873
+ * TEXT_FIELD (session.input.setTextFieldOpen): the app has a text field on
1874
+ * the glasses, or no longer does. Text entry that costs power to leave on
1875
+ * (Neural Band handwriting) runs while any app has one. Cleared on app stop.
1876
+ */
1877
+ handleTextField(packageName, payload, requestId) {
1878
+ if (typeof payload.open !== "boolean") {
1879
+ this.sendResult(packageName, requestId, false, undefined, {
1880
+ code: MiniappErrorCode.INVALID_ARGUMENT,
1881
+ message: "Text field open must be a boolean",
1882
+ });
1883
+ return;
1884
+ }
1885
+ if (this.connectedApps.has(packageName))
1886
+ this.setTextFieldOpen(packageName, payload.open);
1887
+ this.sendResult(packageName, requestId, true);
1888
+ }
1889
+ setTextFieldOpen(packageName, open) {
1890
+ const before = this.textFieldApps.size > 0;
1891
+ if (open)
1892
+ this.textFieldApps.add(packageName);
1893
+ else
1894
+ this.textFieldApps.delete(packageName);
1895
+ const after = this.textFieldApps.size > 0;
1896
+ if (before === after)
1897
+ return;
1898
+ for (const cb of this.textFieldListeners) {
1899
+ try {
1900
+ cb(after);
1901
+ }
1902
+ catch (err) {
1903
+ console.warn(`${LOG_TAG}: text field listener failed:`, err);
1904
+ }
1905
+ }
1906
+ }
1907
+ /** True while any running miniapp has a text field open on the glasses. */
1908
+ hasOpenTextField() {
1909
+ return this.textFieldApps.size > 0;
1910
+ }
1911
+ onTextFieldChange(cb) {
1912
+ this.textFieldListeners.add(cb);
1913
+ return () => this.textFieldListeners.delete(cb);
1914
+ }
1865
1915
  /** The app holding `gesture` (the most recent claimer), or null when it is unclaimed. */
1866
1916
  gestureClaimant(gesture) {
1867
1917
  const claimant = gestureClaimant(this.gestureClaims, gesture);
@@ -3690,8 +3740,8 @@ class LocalMiniappRuntime {
3690
3740
  this.sendResult(packageName, requestId, true, result);
3691
3741
  }
3692
3742
  catch (err) {
3693
- // 402 quota_exceeded from the runtime: the account's monthly AI credit
3694
- // is spent. Distinct code (miniapps may fall back to a local path) and
3743
+ // 402 quota_exceeded from the runtime: the account's AI credits are
3744
+ // spent. Distinct code (miniapps may fall back to a local path) and
3695
3745
  // a host hook so the app can offer the upgrade paywall — the miniapp
3696
3746
  // itself must never own that conversation.
3697
3747
  const quotaExceeded = err instanceof HttpError && (err.code === "quota_exceeded" || err.status === 402);
@@ -3734,6 +3784,12 @@ class LocalMiniappRuntime {
3734
3784
  */
3735
3785
  async serveLocalAi(packageName, requestId, request, reason, primaryError) {
3736
3786
  const modelId = localLlmModelManager.selectedModelId();
3787
+ const unusable = localLlmModelManager.unusableReason(modelId);
3788
+ if (unusable) {
3789
+ console.warn(`${LOG_TAG}: ai.complete on-device for ${packageName} (${reason}): ${unusable}`);
3790
+ this.sendResult(packageName, requestId, false, undefined, primaryError ?? { code: MiniappErrorCode.AI_LOCAL_UNAVAILABLE, message: unusable });
3791
+ return;
3792
+ }
3737
3793
  if (!(await localLlmModelManager.ensureSelectedModel())) {
3738
3794
  const status = localLlmModelManager.getStatus();
3739
3795
  const state = status?.modelId === modelId && status.stage === "downloading"
@@ -3744,7 +3800,7 @@ class LocalMiniappRuntime {
3744
3800
  console.warn(`${LOG_TAG}: ai.complete on-device for ${packageName} (${reason}): model ${modelId} ${state}`);
3745
3801
  this.sendResult(packageName, requestId, false, undefined, primaryError ?? {
3746
3802
  code: MiniappErrorCode.AI_LOCAL_UNAVAILABLE,
3747
- message: `The on-device model (${localLlmModelManager.model(modelId).label}) ${state}. Manage it in Settings > AI Models.`,
3803
+ message: `The on-device model (${localLlmModelManager.model(modelId).label}) ${state}. Manage it in Settings > Offline Models.`,
3748
3804
  });
3749
3805
  return;
3750
3806
  }
@@ -3818,7 +3874,7 @@ class LocalMiniappRuntime {
3818
3874
  this.onQuotaExceeded?.("llm");
3819
3875
  this.sendResult(packageName, requestId, false, undefined, {
3820
3876
  code: MiniappErrorCode.QUOTA_EXCEEDED,
3821
- message: "Monthly AI credit is used up. Upgrade in Settings > Membership, or add your own API key in Settings > API Keys.",
3877
+ message: "AI credits are used up. Get more in Settings > Membership, or add your own API key in Settings > API Keys.",
3822
3878
  });
3823
3879
  return;
3824
3880
  }