@ateam-ai-mobile/plugin-runtime 0.1.21 → 0.1.22

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/dist/index.d.mts CHANGED
@@ -1253,6 +1253,9 @@ interface AiLiveEpisode {
1253
1253
  /** The task class id from the chosen setup, e.g. "drinking". */
1254
1254
  class: string;
1255
1255
  episodeId: string;
1256
+ /** Whose camera saw it: the signed-in person whose live session this is (live sessions are per
1257
+ * person, workspace + actor). Always there: an event without it never reaches the screen. */
1258
+ actorId: string;
1256
1259
  /** When (ms since the epoch, the session's clock). */
1257
1260
  at: number;
1258
1261
  [key: string]: unknown;
@@ -1264,7 +1267,7 @@ type AiLiveState =
1264
1267
  | 'starting'
1265
1268
  /** Pictures are going to the AI ("Sending to AI" is on screen). */
1266
1269
  | 'sending'
1267
- /** Stopped by stop() or by the screen closing. */
1270
+ /** Stopped by stop(), by the screen closing, or by the person taking the yes back (lastError says so). */
1268
1271
  | 'stopped'
1269
1272
  /** It could not start or it broke; `lastError` says why in plain words. */
1270
1273
  | 'error';
@@ -1283,8 +1286,10 @@ interface AiLiveStartOptions {
1283
1286
  camera?: AiLiveCamera;
1284
1287
  }
1285
1288
  interface AiLiveAPI {
1286
- /** Start sending this phone's camera to the chosen AI. Refuses by name when either
1287
- * side has not said yes, or when another screen is sending already. */
1289
+ /** Start sending this phone's camera to the chosen AI, in a live session of the
1290
+ * phone's own (capped at US$0.50). Refuses by name when either side has not said
1291
+ * yes, when another screen is sending already, or when the person already has a
1292
+ * live session running elsewhere. */
1288
1293
  start(opts?: AiLiveStartOptions): Promise<AiLiveSnapshot>;
1289
1294
  /** Stop sending. Closing the screen does the same. */
1290
1295
  stop(): Promise<void>;
@@ -1297,10 +1302,14 @@ interface AiLiveAPI {
1297
1302
  /** What the host supplies (setAiLiveProvider). `owner` is the screen's holder id,
1298
1303
  * captured by the gate — a plugin never supplies its own. */
1299
1304
  interface AiLiveProvider {
1305
+ /** `ctx.allowed` is the two-sided consent, asked again right before every picture:
1306
+ * once it answers no, the provider sends nothing more and stops. */
1300
1307
  start(opts: AiLiveStartOptions, owner: string, ctx: {
1301
1308
  visual: DeviceState['visual'];
1309
+ allowed: () => boolean;
1302
1310
  }): Promise<AiLiveSnapshot>;
1303
- stop(owner: string): Promise<void>;
1311
+ /** `why` (optional) is what the screen then reads as lastError, e.g. the yes taken back. */
1312
+ stop(owner: string, why?: string): Promise<void>;
1304
1313
  getSnapshot(owner: string): AiLiveSnapshot;
1305
1314
  onEpisode(cb: (ev: AiLiveEpisode) => void, owner: string): Subscription;
1306
1315
  subscribe(cb: (snap: AiLiveSnapshot) => void, owner: string): Subscription;
@@ -2368,6 +2377,8 @@ declare function implementedVoice(): boolean;
2368
2377
  */
2369
2378
  declare function gateVoice(declared: boolean, pluginId: string): VoiceAPI;
2370
2379
 
2380
+ /** The person took the yes back: what the screen reads, and why it stopped. */
2381
+ declare const CONSENT_TAKEN_BACK = "Camera pictures to AI was turned off on this phone, so sending stopped.";
2371
2382
  /** Host DI: the app supplies the live provider once at startup; null detaches it. */
2372
2383
  declare function setAiLiveProvider(provider: AiLiveProvider | null): void;
2373
2384
  /**
@@ -2378,7 +2389,9 @@ declare function setAiLiveProvider(provider: AiLiveProvider | null): void;
2378
2389
  * never reaches the plugin: the plugin gets episodes, the sender gets the camera.
2379
2390
  */
2380
2391
  declare function gateAiLive(capabilities: NativeCapabilities$1 | undefined, pluginId: string, holder: string, camera: () => DeviceState['visual']): AiLiveAPI;
2381
- /** The screen closed: stop its live session and release its camera. */
2392
+ /** The screen closed: stop its live session and release its camera, and keep nothing of it. Closed for
2393
+ * good first, so every later start() of this screen is refused; then, in turn after anything it asked
2394
+ * before, the session stopped and the camera released. */
2382
2395
  declare function releaseAiLive(holder: string): Promise<void>;
2383
2396
  /** For the platform's "Sending to AI" indicator: is any screen sending, and when that changes. */
2384
2397
  declare const aiLiveIndicator: {
@@ -2426,6 +2439,14 @@ declare function getCameraPreviewProvider(): ((props: CameraPreviewImplProps) =>
2426
2439
  /** Install the host's answer to "did the person on this phone allow camera
2427
2440
  * pictures to go to AI?". Pass null to remove it (consent then reads as no). */
2428
2441
  declare function setPicturesToAiConsentProvider(provider: (() => boolean) | null): void;
2442
+ /** The host calls this whenever anything its consent answer reads may have changed
2443
+ * (the switch, the camera's own switch, the OS permission). Listeners re-ask
2444
+ * mayPicturesLeavePhone(); nothing is passed, so nothing can be cached. */
2445
+ declare function notifyPicturesToAiConsentChanged(): void;
2446
+ /** Hear when the consent answer may have changed (see notifyPicturesToAiConsentChanged). */
2447
+ declare function onPicturesToAiConsentChange(cb: () => void): {
2448
+ unsubscribe(): void;
2449
+ };
2429
2450
  /** The one check: true only when the plugin's trusted declaration includes
2430
2451
  * `picturesToAi` AND the person on the phone allowed it right now. */
2431
2452
  declare function mayPicturesLeavePhone(declared?: NativeCapabilities$1 | null): boolean;
@@ -3454,4 +3475,4 @@ declare function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest
3454
3475
 
3455
3476
  declare function SurfaceDispatcher(): react_jsx_runtime.JSX.Element;
3456
3477
 
3457
- export { AI_LIVE_IDLE, ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, type AiLiveAPI, type AiLiveCamera, type AiLiveEpisode, type AiLiveProvider, type AiLiveSnapshot, type AiLiveStartOptions, type AiLiveState, Badge, type BiometricsAPI, type BiometricsAPIv2, type BluetoothAPI, type BluetoothDevice, type Bridge, type BundleCacheEntry, type BundleStorage, type CameraAPI, CameraPreview, type CameraPreviewProps, type CapabilitySnapshot, type CapabilityStatus, Card, type Confidence, type ConnectivityAPI, type ConnectivitySnapshot, type CookiesAPI, type DeviceBridgeDomain, type DeviceContextSnapshot, type DeviceState, type DeviceToolContext, type DeviceToolDefinition, type DeviceToolFailureReason, type DeviceToolFn, type DeviceToolOutcome, type DeviceToolSummary, type DeviceToolsAction, type DeviceToolsSessionDeps, EmptyState, type EnvironmentSnapshot, ErrorState, type FileSystemAPI, type Freshness, type HapticsAPI, type InlineSurfaceManifest, type InteractionSnapshot, ListItem, type LoadedBundleInfo, type LoadedBundleSource, LoadingState, type LocationAPI, type MapsAPI, type MapsAddress, type MapsCoordinate, type MapsPlace, type MapsRoute, type MapsRouteStep, MemoryBundleStorage, type MountSurfaceManifest, type NativeCapabilities$1 as NativeCapabilities, type NfcAPI, type NotificationsAPI, PLATFORM_VOICE_CALLER, type PluginManifest as PlatformPluginManifest, type PluginBridge, type PluginContext, type PluginGrants, type PluginHooks$1 as PluginHooks, type PluginManifest$1 as PluginManifest, type PluginNative, type PluginProps, type PluginRuntimeProps, type PluginRuntimeSource, PluginSDK, type PluginSummary, type PluginSurfaceMeta, type RegisteredPlugin, type RegisteredServicePlugin, type RegisteredToolsPlugin, type RegisteredUIPlugin, type RemotePlugin, type RenderMode, type ScannerAPI, SearchBar, type SessionSnapshot, type SharingAPI, type SpatialEvent, type SpatialIntent, type SpatialPoint, type SpatialSnapshot, type SpatialStateEvent, type StateEvent, type StateListener, type StateQuality, type StorageAPI, type Subscription, SurfaceCard, type SurfaceCardProps, SurfaceDispatcher, SurfaceDrawer, type SurfaceDrawerProps, SurfaceFullscreen, type SurfaceFullscreenProps, type SurfaceManifest, type SurfacePlacement, type SurfaceType, type SurfaceVisibility, TabBar, type ThemeTokens, type TrustedToolDeclaration, type VisionAPI, type VisionFrameQuality, type VisionLabel, type VisionObject, type VisionText, type VisualSnapshot, type VisualStartOptions, type VoiceAPI, type VoiceCaller, type VoiceDeviceToolCall, type VoiceDeviceToolReason, type VoiceEvent, type VoicePersona, type VoiceSessionProvider, type VoiceSnapshot, type VoiceStartOptions, type VoiceState, type VoiceSubscription, type VoiceTranscriptEntry, type WebViewCookie, __resetSessionSyncForTest, aiLiveIndicator, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateAiLive, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, mayPicturesLeavePhone, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseAiLive, releaseDeviceStateHolds, rendersNative, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setAiLiveProvider, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPicturesToAiConsentProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
3478
+ export { AI_LIVE_IDLE, ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, type AiLiveAPI, type AiLiveCamera, type AiLiveEpisode, type AiLiveProvider, type AiLiveSnapshot, type AiLiveStartOptions, type AiLiveState, Badge, type BiometricsAPI, type BiometricsAPIv2, type BluetoothAPI, type BluetoothDevice, type Bridge, type BundleCacheEntry, type BundleStorage, CONSENT_TAKEN_BACK, type CameraAPI, CameraPreview, type CameraPreviewProps, type CapabilitySnapshot, type CapabilityStatus, Card, type Confidence, type ConnectivityAPI, type ConnectivitySnapshot, type CookiesAPI, type DeviceBridgeDomain, type DeviceContextSnapshot, type DeviceState, type DeviceToolContext, type DeviceToolDefinition, type DeviceToolFailureReason, type DeviceToolFn, type DeviceToolOutcome, type DeviceToolSummary, type DeviceToolsAction, type DeviceToolsSessionDeps, EmptyState, type EnvironmentSnapshot, ErrorState, type FileSystemAPI, type Freshness, type HapticsAPI, type InlineSurfaceManifest, type InteractionSnapshot, ListItem, type LoadedBundleInfo, type LoadedBundleSource, LoadingState, type LocationAPI, type MapsAPI, type MapsAddress, type MapsCoordinate, type MapsPlace, type MapsRoute, type MapsRouteStep, MemoryBundleStorage, type MountSurfaceManifest, type NativeCapabilities$1 as NativeCapabilities, type NfcAPI, type NotificationsAPI, PLATFORM_VOICE_CALLER, type PluginManifest as PlatformPluginManifest, type PluginBridge, type PluginContext, type PluginGrants, type PluginHooks$1 as PluginHooks, type PluginManifest$1 as PluginManifest, type PluginNative, type PluginProps, type PluginRuntimeProps, type PluginRuntimeSource, PluginSDK, type PluginSummary, type PluginSurfaceMeta, type RegisteredPlugin, type RegisteredServicePlugin, type RegisteredToolsPlugin, type RegisteredUIPlugin, type RemotePlugin, type RenderMode, type ScannerAPI, SearchBar, type SessionSnapshot, type SharingAPI, type SpatialEvent, type SpatialIntent, type SpatialPoint, type SpatialSnapshot, type SpatialStateEvent, type StateEvent, type StateListener, type StateQuality, type StorageAPI, type Subscription, SurfaceCard, type SurfaceCardProps, SurfaceDispatcher, SurfaceDrawer, type SurfaceDrawerProps, SurfaceFullscreen, type SurfaceFullscreenProps, type SurfaceManifest, type SurfacePlacement, type SurfaceType, type SurfaceVisibility, TabBar, type ThemeTokens, type TrustedToolDeclaration, type VisionAPI, type VisionFrameQuality, type VisionLabel, type VisionObject, type VisionText, type VisualSnapshot, type VisualStartOptions, type VoiceAPI, type VoiceCaller, type VoiceDeviceToolCall, type VoiceDeviceToolReason, type VoiceEvent, type VoicePersona, type VoiceSessionProvider, type VoiceSnapshot, type VoiceStartOptions, type VoiceState, type VoiceSubscription, type VoiceTranscriptEntry, type WebViewCookie, __resetSessionSyncForTest, aiLiveIndicator, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateAiLive, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, mayPicturesLeavePhone, nativePluginRegistry, neverObserved, notifyPicturesToAiConsentChanged, onPicturesToAiConsentChange, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseAiLive, releaseDeviceStateHolds, rendersNative, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setAiLiveProvider, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPicturesToAiConsentProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
package/dist/index.d.ts CHANGED
@@ -1253,6 +1253,9 @@ interface AiLiveEpisode {
1253
1253
  /** The task class id from the chosen setup, e.g. "drinking". */
1254
1254
  class: string;
1255
1255
  episodeId: string;
1256
+ /** Whose camera saw it: the signed-in person whose live session this is (live sessions are per
1257
+ * person, workspace + actor). Always there: an event without it never reaches the screen. */
1258
+ actorId: string;
1256
1259
  /** When (ms since the epoch, the session's clock). */
1257
1260
  at: number;
1258
1261
  [key: string]: unknown;
@@ -1264,7 +1267,7 @@ type AiLiveState =
1264
1267
  | 'starting'
1265
1268
  /** Pictures are going to the AI ("Sending to AI" is on screen). */
1266
1269
  | 'sending'
1267
- /** Stopped by stop() or by the screen closing. */
1270
+ /** Stopped by stop(), by the screen closing, or by the person taking the yes back (lastError says so). */
1268
1271
  | 'stopped'
1269
1272
  /** It could not start or it broke; `lastError` says why in plain words. */
1270
1273
  | 'error';
@@ -1283,8 +1286,10 @@ interface AiLiveStartOptions {
1283
1286
  camera?: AiLiveCamera;
1284
1287
  }
1285
1288
  interface AiLiveAPI {
1286
- /** Start sending this phone's camera to the chosen AI. Refuses by name when either
1287
- * side has not said yes, or when another screen is sending already. */
1289
+ /** Start sending this phone's camera to the chosen AI, in a live session of the
1290
+ * phone's own (capped at US$0.50). Refuses by name when either side has not said
1291
+ * yes, when another screen is sending already, or when the person already has a
1292
+ * live session running elsewhere. */
1288
1293
  start(opts?: AiLiveStartOptions): Promise<AiLiveSnapshot>;
1289
1294
  /** Stop sending. Closing the screen does the same. */
1290
1295
  stop(): Promise<void>;
@@ -1297,10 +1302,14 @@ interface AiLiveAPI {
1297
1302
  /** What the host supplies (setAiLiveProvider). `owner` is the screen's holder id,
1298
1303
  * captured by the gate — a plugin never supplies its own. */
1299
1304
  interface AiLiveProvider {
1305
+ /** `ctx.allowed` is the two-sided consent, asked again right before every picture:
1306
+ * once it answers no, the provider sends nothing more and stops. */
1300
1307
  start(opts: AiLiveStartOptions, owner: string, ctx: {
1301
1308
  visual: DeviceState['visual'];
1309
+ allowed: () => boolean;
1302
1310
  }): Promise<AiLiveSnapshot>;
1303
- stop(owner: string): Promise<void>;
1311
+ /** `why` (optional) is what the screen then reads as lastError, e.g. the yes taken back. */
1312
+ stop(owner: string, why?: string): Promise<void>;
1304
1313
  getSnapshot(owner: string): AiLiveSnapshot;
1305
1314
  onEpisode(cb: (ev: AiLiveEpisode) => void, owner: string): Subscription;
1306
1315
  subscribe(cb: (snap: AiLiveSnapshot) => void, owner: string): Subscription;
@@ -2368,6 +2377,8 @@ declare function implementedVoice(): boolean;
2368
2377
  */
2369
2378
  declare function gateVoice(declared: boolean, pluginId: string): VoiceAPI;
2370
2379
 
2380
+ /** The person took the yes back: what the screen reads, and why it stopped. */
2381
+ declare const CONSENT_TAKEN_BACK = "Camera pictures to AI was turned off on this phone, so sending stopped.";
2371
2382
  /** Host DI: the app supplies the live provider once at startup; null detaches it. */
2372
2383
  declare function setAiLiveProvider(provider: AiLiveProvider | null): void;
2373
2384
  /**
@@ -2378,7 +2389,9 @@ declare function setAiLiveProvider(provider: AiLiveProvider | null): void;
2378
2389
  * never reaches the plugin: the plugin gets episodes, the sender gets the camera.
2379
2390
  */
2380
2391
  declare function gateAiLive(capabilities: NativeCapabilities$1 | undefined, pluginId: string, holder: string, camera: () => DeviceState['visual']): AiLiveAPI;
2381
- /** The screen closed: stop its live session and release its camera. */
2392
+ /** The screen closed: stop its live session and release its camera, and keep nothing of it. Closed for
2393
+ * good first, so every later start() of this screen is refused; then, in turn after anything it asked
2394
+ * before, the session stopped and the camera released. */
2382
2395
  declare function releaseAiLive(holder: string): Promise<void>;
2383
2396
  /** For the platform's "Sending to AI" indicator: is any screen sending, and when that changes. */
2384
2397
  declare const aiLiveIndicator: {
@@ -2426,6 +2439,14 @@ declare function getCameraPreviewProvider(): ((props: CameraPreviewImplProps) =>
2426
2439
  /** Install the host's answer to "did the person on this phone allow camera
2427
2440
  * pictures to go to AI?". Pass null to remove it (consent then reads as no). */
2428
2441
  declare function setPicturesToAiConsentProvider(provider: (() => boolean) | null): void;
2442
+ /** The host calls this whenever anything its consent answer reads may have changed
2443
+ * (the switch, the camera's own switch, the OS permission). Listeners re-ask
2444
+ * mayPicturesLeavePhone(); nothing is passed, so nothing can be cached. */
2445
+ declare function notifyPicturesToAiConsentChanged(): void;
2446
+ /** Hear when the consent answer may have changed (see notifyPicturesToAiConsentChanged). */
2447
+ declare function onPicturesToAiConsentChange(cb: () => void): {
2448
+ unsubscribe(): void;
2449
+ };
2429
2450
  /** The one check: true only when the plugin's trusted declaration includes
2430
2451
  * `picturesToAi` AND the person on the phone allowed it right now. */
2431
2452
  declare function mayPicturesLeavePhone(declared?: NativeCapabilities$1 | null): boolean;
@@ -3454,4 +3475,4 @@ declare function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest
3454
3475
 
3455
3476
  declare function SurfaceDispatcher(): react_jsx_runtime.JSX.Element;
3456
3477
 
3457
- export { AI_LIVE_IDLE, ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, type AiLiveAPI, type AiLiveCamera, type AiLiveEpisode, type AiLiveProvider, type AiLiveSnapshot, type AiLiveStartOptions, type AiLiveState, Badge, type BiometricsAPI, type BiometricsAPIv2, type BluetoothAPI, type BluetoothDevice, type Bridge, type BundleCacheEntry, type BundleStorage, type CameraAPI, CameraPreview, type CameraPreviewProps, type CapabilitySnapshot, type CapabilityStatus, Card, type Confidence, type ConnectivityAPI, type ConnectivitySnapshot, type CookiesAPI, type DeviceBridgeDomain, type DeviceContextSnapshot, type DeviceState, type DeviceToolContext, type DeviceToolDefinition, type DeviceToolFailureReason, type DeviceToolFn, type DeviceToolOutcome, type DeviceToolSummary, type DeviceToolsAction, type DeviceToolsSessionDeps, EmptyState, type EnvironmentSnapshot, ErrorState, type FileSystemAPI, type Freshness, type HapticsAPI, type InlineSurfaceManifest, type InteractionSnapshot, ListItem, type LoadedBundleInfo, type LoadedBundleSource, LoadingState, type LocationAPI, type MapsAPI, type MapsAddress, type MapsCoordinate, type MapsPlace, type MapsRoute, type MapsRouteStep, MemoryBundleStorage, type MountSurfaceManifest, type NativeCapabilities$1 as NativeCapabilities, type NfcAPI, type NotificationsAPI, PLATFORM_VOICE_CALLER, type PluginManifest as PlatformPluginManifest, type PluginBridge, type PluginContext, type PluginGrants, type PluginHooks$1 as PluginHooks, type PluginManifest$1 as PluginManifest, type PluginNative, type PluginProps, type PluginRuntimeProps, type PluginRuntimeSource, PluginSDK, type PluginSummary, type PluginSurfaceMeta, type RegisteredPlugin, type RegisteredServicePlugin, type RegisteredToolsPlugin, type RegisteredUIPlugin, type RemotePlugin, type RenderMode, type ScannerAPI, SearchBar, type SessionSnapshot, type SharingAPI, type SpatialEvent, type SpatialIntent, type SpatialPoint, type SpatialSnapshot, type SpatialStateEvent, type StateEvent, type StateListener, type StateQuality, type StorageAPI, type Subscription, SurfaceCard, type SurfaceCardProps, SurfaceDispatcher, SurfaceDrawer, type SurfaceDrawerProps, SurfaceFullscreen, type SurfaceFullscreenProps, type SurfaceManifest, type SurfacePlacement, type SurfaceType, type SurfaceVisibility, TabBar, type ThemeTokens, type TrustedToolDeclaration, type VisionAPI, type VisionFrameQuality, type VisionLabel, type VisionObject, type VisionText, type VisualSnapshot, type VisualStartOptions, type VoiceAPI, type VoiceCaller, type VoiceDeviceToolCall, type VoiceDeviceToolReason, type VoiceEvent, type VoicePersona, type VoiceSessionProvider, type VoiceSnapshot, type VoiceStartOptions, type VoiceState, type VoiceSubscription, type VoiceTranscriptEntry, type WebViewCookie, __resetSessionSyncForTest, aiLiveIndicator, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateAiLive, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, mayPicturesLeavePhone, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseAiLive, releaseDeviceStateHolds, rendersNative, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setAiLiveProvider, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPicturesToAiConsentProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
3478
+ export { AI_LIVE_IDLE, ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, type AiLiveAPI, type AiLiveCamera, type AiLiveEpisode, type AiLiveProvider, type AiLiveSnapshot, type AiLiveStartOptions, type AiLiveState, Badge, type BiometricsAPI, type BiometricsAPIv2, type BluetoothAPI, type BluetoothDevice, type Bridge, type BundleCacheEntry, type BundleStorage, CONSENT_TAKEN_BACK, type CameraAPI, CameraPreview, type CameraPreviewProps, type CapabilitySnapshot, type CapabilityStatus, Card, type Confidence, type ConnectivityAPI, type ConnectivitySnapshot, type CookiesAPI, type DeviceBridgeDomain, type DeviceContextSnapshot, type DeviceState, type DeviceToolContext, type DeviceToolDefinition, type DeviceToolFailureReason, type DeviceToolFn, type DeviceToolOutcome, type DeviceToolSummary, type DeviceToolsAction, type DeviceToolsSessionDeps, EmptyState, type EnvironmentSnapshot, ErrorState, type FileSystemAPI, type Freshness, type HapticsAPI, type InlineSurfaceManifest, type InteractionSnapshot, ListItem, type LoadedBundleInfo, type LoadedBundleSource, LoadingState, type LocationAPI, type MapsAPI, type MapsAddress, type MapsCoordinate, type MapsPlace, type MapsRoute, type MapsRouteStep, MemoryBundleStorage, type MountSurfaceManifest, type NativeCapabilities$1 as NativeCapabilities, type NfcAPI, type NotificationsAPI, PLATFORM_VOICE_CALLER, type PluginManifest as PlatformPluginManifest, type PluginBridge, type PluginContext, type PluginGrants, type PluginHooks$1 as PluginHooks, type PluginManifest$1 as PluginManifest, type PluginNative, type PluginProps, type PluginRuntimeProps, type PluginRuntimeSource, PluginSDK, type PluginSummary, type PluginSurfaceMeta, type RegisteredPlugin, type RegisteredServicePlugin, type RegisteredToolsPlugin, type RegisteredUIPlugin, type RemotePlugin, type RenderMode, type ScannerAPI, SearchBar, type SessionSnapshot, type SharingAPI, type SpatialEvent, type SpatialIntent, type SpatialPoint, type SpatialSnapshot, type SpatialStateEvent, type StateEvent, type StateListener, type StateQuality, type StorageAPI, type Subscription, SurfaceCard, type SurfaceCardProps, SurfaceDispatcher, SurfaceDrawer, type SurfaceDrawerProps, SurfaceFullscreen, type SurfaceFullscreenProps, type SurfaceManifest, type SurfacePlacement, type SurfaceType, type SurfaceVisibility, TabBar, type ThemeTokens, type TrustedToolDeclaration, type VisionAPI, type VisionFrameQuality, type VisionLabel, type VisionObject, type VisionText, type VisualSnapshot, type VisualStartOptions, type VoiceAPI, type VoiceCaller, type VoiceDeviceToolCall, type VoiceDeviceToolReason, type VoiceEvent, type VoicePersona, type VoiceSessionProvider, type VoiceSnapshot, type VoiceStartOptions, type VoiceState, type VoiceSubscription, type VoiceTranscriptEntry, type WebViewCookie, __resetSessionSyncForTest, aiLiveIndicator, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateAiLive, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, mayPicturesLeavePhone, nativePluginRegistry, neverObserved, notifyPicturesToAiConsentChanged, onPicturesToAiConsentChange, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseAiLive, releaseDeviceStateHolds, rendersNative, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setAiLiveProvider, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPicturesToAiConsentProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
package/dist/index.js CHANGED
@@ -495,6 +495,21 @@ function getCameraPreviewProvider() {
495
495
  }
496
496
  function setPicturesToAiConsentProvider(provider) {
497
497
  _picturesToAiConsent = provider;
498
+ notifyPicturesToAiConsentChanged();
499
+ }
500
+ function notifyPicturesToAiConsentChanged() {
501
+ for (const cb of [..._consentListeners]) {
502
+ try {
503
+ cb();
504
+ } catch {
505
+ }
506
+ }
507
+ }
508
+ function onPicturesToAiConsentChange(cb) {
509
+ _consentListeners.add(cb);
510
+ return { unsubscribe: () => {
511
+ _consentListeners.delete(cb);
512
+ } };
498
513
  }
499
514
  function mayPicturesLeavePhone(declared) {
500
515
  if (declared?.picturesToAi !== true) return false;
@@ -526,7 +541,7 @@ function registerBundleModules(modules) {
526
541
  function resolveBundleModule(name) {
527
542
  return _bundleModules.get(name);
528
543
  }
529
- var _haptics, noopNative, _pluginNative, _cameraPreview, _picturesToAiConsent, _nativeRegistry, nativePluginRegistry, _bundleModules;
544
+ var _haptics, noopNative, _pluginNative, _cameraPreview, _picturesToAiConsent, _consentListeners, _nativeRegistry, nativePluginRegistry, _bundleModules;
530
545
  var init_host = __esm({
531
546
  "src/host.ts"() {
532
547
  "use strict";
@@ -557,6 +572,7 @@ var init_host = __esm({
557
572
  _pluginNative = noopNative;
558
573
  _cameraPreview = null;
559
574
  _picturesToAiConsent = null;
575
+ _consentListeners = /* @__PURE__ */ new Set();
560
576
  _nativeRegistry = /* @__PURE__ */ new Map();
561
577
  nativePluginRegistry = {
562
578
  has(id) {
@@ -1096,6 +1112,21 @@ var init_voiceHost = __esm({
1096
1112
  });
1097
1113
 
1098
1114
  // src/aiLiveHost.ts
1115
+ function screenOf(holder) {
1116
+ let sc = _screens.get(holder);
1117
+ if (!sc) {
1118
+ sc = { closed: false, stops: 0, queue: Promise.resolve(), watch: null };
1119
+ _screens.set(holder, sc);
1120
+ }
1121
+ return sc;
1122
+ }
1123
+ function inTurn(sc, step) {
1124
+ const run = sc.queue.then(step, step);
1125
+ sc.queue = run.then(() => {
1126
+ }, () => {
1127
+ });
1128
+ return run;
1129
+ }
1099
1130
  function setAiLiveProvider(provider) {
1100
1131
  _provider3 = provider || null;
1101
1132
  }
@@ -1125,53 +1156,117 @@ function deniedAiLive(why) {
1125
1156
  }
1126
1157
  function gateAiLive(capabilities, pluginId, holder, camera) {
1127
1158
  if (capabilities?.picturesToAi !== true) {
1128
- return deniedAiLive("not declared in this plugin's capabilities. Add `capabilities: { picturesToAi: true }` to send camera pictures to the workspace's chosen AI.");
1159
+ return deniedAiLive("not declared in this plugin's manifest. Add `native: { picturesToAi: true }` to send camera pictures to the workspace's chosen AI.");
1129
1160
  }
1130
1161
  if (!pluginId || !holder) return deniedAiLive("no plugin identity \u2014 it fails closed without a screen to bind the session to.");
1131
1162
  if (!_provider3) return deniedAiLive("no live AI in this build \u2014 the app has not called setAiLiveProvider.");
1132
1163
  const provider = _provider3;
1164
+ const sc = screenOf(holder);
1165
+ const allowed = () => mayPicturesLeavePhone(capabilities);
1166
+ const releaseCamera = () => releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1167
+ const tidy = async (why) => {
1168
+ unwatch(sc);
1169
+ try {
1170
+ await provider.stop(holder, why);
1171
+ } finally {
1172
+ await releaseCamera();
1173
+ }
1174
+ };
1175
+ const stopNowAndInTurn = (why) => {
1176
+ sc.stops++;
1177
+ const now = provider.stop(holder, why).catch(() => {
1178
+ });
1179
+ return inTurn(sc, async () => {
1180
+ await now;
1181
+ await tidy(why);
1182
+ });
1183
+ };
1184
+ const onConsentChange = () => {
1185
+ if (!allowed()) void stopNowAndInTurn(CONSENT_TAKEN_BACK);
1186
+ };
1133
1187
  return {
1134
- async start(opts) {
1135
- if (!mayPicturesLeavePhone(capabilities)) {
1136
- throw denial2(`the person on this phone has not allowed camera pictures to go to AI. They can turn on "Pictures to AI" in the app's settings (What Ada can access).`);
1137
- }
1138
- try {
1139
- return await provider.start(opts || {}, holder, { visual: camera() });
1140
- } catch (e) {
1141
- await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1142
- throw e;
1143
- }
1144
- },
1145
- async stop() {
1146
- try {
1147
- await provider.stop(holder);
1148
- } finally {
1149
- await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1150
- }
1188
+ start(opts) {
1189
+ if (sc.closed) return Promise.reject(stopped(SCREEN_CLOSED));
1190
+ const stopsWhenAsked = sc.stops;
1191
+ return inTurn(sc, async () => {
1192
+ if (sc.closed) throw stopped(SCREEN_CLOSED);
1193
+ if (sc.stops !== stopsWhenAsked) throw stopped(STOPPED_BEFORE_START);
1194
+ if (!allowed()) {
1195
+ throw denial2('the person on this phone has not allowed camera pictures to go to AI. They can turn on Settings > Camera > "Camera pictures to AI" in the app.');
1196
+ }
1197
+ unwatch(sc);
1198
+ sc.watch = onPicturesToAiConsentChange(onConsentChange);
1199
+ let snap;
1200
+ try {
1201
+ snap = await provider.start(opts || {}, holder, { visual: camera(), allowed });
1202
+ } catch (e) {
1203
+ unwatch(sc);
1204
+ await releaseCamera();
1205
+ if (!allowed()) throw denial2(CONSENT_TAKEN_BACK);
1206
+ throw e;
1207
+ }
1208
+ if (!allowed()) {
1209
+ await tidy(CONSENT_TAKEN_BACK);
1210
+ throw denial2(CONSENT_TAKEN_BACK);
1211
+ }
1212
+ return snap;
1213
+ });
1151
1214
  },
1215
+ stop: () => stopNowAndInTurn(),
1152
1216
  getSnapshot: () => provider.getSnapshot(holder),
1153
1217
  onEpisode: (cb) => provider.onEpisode(cb, holder),
1154
1218
  subscribe: (cb) => provider.subscribe(cb, holder)
1155
1219
  };
1156
1220
  }
1157
1221
  async function releaseAiLive(holder) {
1158
- try {
1159
- await _provider3?.stop(holder);
1160
- } catch {
1161
- }
1162
- try {
1163
- _provider3?.forget(holder);
1164
- } catch {
1222
+ const sc = _screens.get(holder);
1223
+ if (!sc) {
1224
+ try {
1225
+ await _provider3?.stop(holder);
1226
+ } catch {
1227
+ }
1228
+ try {
1229
+ _provider3?.forget(holder);
1230
+ } catch {
1231
+ }
1232
+ await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1233
+ return;
1165
1234
  }
1166
- await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1235
+ sc.closed = true;
1236
+ sc.stops++;
1237
+ const now = _provider3 ? _provider3.stop(holder).catch(() => {
1238
+ }) : Promise.resolve();
1239
+ await inTurn(sc, async () => {
1240
+ await now;
1241
+ unwatch(sc);
1242
+ try {
1243
+ await _provider3?.stop(holder);
1244
+ } catch {
1245
+ }
1246
+ try {
1247
+ _provider3?.forget(holder);
1248
+ } catch {
1249
+ }
1250
+ await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
1251
+ });
1252
+ if (_screens.get(holder) === sc) _screens.delete(holder);
1167
1253
  }
1168
- var _provider3, aiLiveCameraHolder, NOTHING, aiLiveIndicator;
1254
+ var _provider3, _screens, unwatch, STOPPED_BEFORE_START, SCREEN_CLOSED, stopped, CONSENT_TAKEN_BACK, aiLiveCameraHolder, NOTHING, aiLiveIndicator;
1169
1255
  var init_aiLiveHost = __esm({
1170
1256
  "src/aiLiveHost.ts"() {
1171
1257
  "use strict";
1172
1258
  init_host();
1173
1259
  init_deviceStateHost();
1174
1260
  _provider3 = null;
1261
+ _screens = /* @__PURE__ */ new Map();
1262
+ unwatch = (sc) => {
1263
+ sc.watch?.unsubscribe();
1264
+ sc.watch = null;
1265
+ };
1266
+ STOPPED_BEFORE_START = "aiLive: stopped before it started: the screen stopped or closed while its start was waiting.";
1267
+ SCREEN_CLOSED = "aiLive: this screen is closed; it cannot start sending.";
1268
+ stopped = (msg) => Object.assign(new Error(msg), { code: "STOPPED" });
1269
+ CONSENT_TAKEN_BACK = "Camera pictures to AI was turned off on this phone, so sending stopped.";
1175
1270
  aiLiveCameraHolder = (holder) => `${holder}#aiLive`;
1176
1271
  NOTHING = { unsubscribe() {
1177
1272
  } };
@@ -3452,6 +3547,7 @@ __export(index_exports, {
3452
3547
  AdaOrb: () => AdaOrb,
3453
3548
  Animated: () => import_react_native.Animated,
3454
3549
  Badge: () => Badge,
3550
+ CONSENT_TAKEN_BACK: () => CONSENT_TAKEN_BACK,
3455
3551
  CameraPreview: () => CameraPreview,
3456
3552
  Card: () => Card,
3457
3553
  EmptyState: () => EmptyState,
@@ -3516,6 +3612,8 @@ __export(index_exports, {
3516
3612
  mayPicturesLeavePhone: () => mayPicturesLeavePhone,
3517
3613
  nativePluginRegistry: () => nativePluginRegistry,
3518
3614
  neverObserved: () => neverObserved,
3615
+ notifyPicturesToAiConsentChanged: () => notifyPicturesToAiConsentChanged,
3616
+ onPicturesToAiConsentChange: () => onPicturesToAiConsentChange,
3519
3617
  pluginBundleUrl: () => pluginBundleUrl,
3520
3618
  register: () => register,
3521
3619
  registerBundleModules: () => registerBundleModules,
@@ -3899,6 +3997,7 @@ init_SurfaceDispatcher();
3899
3997
  AdaOrb,
3900
3998
  Animated,
3901
3999
  Badge,
4000
+ CONSENT_TAKEN_BACK,
3902
4001
  CameraPreview,
3903
4002
  Card,
3904
4003
  EmptyState,
@@ -3963,6 +4062,8 @@ init_SurfaceDispatcher();
3963
4062
  mayPicturesLeavePhone,
3964
4063
  nativePluginRegistry,
3965
4064
  neverObserved,
4065
+ notifyPicturesToAiConsentChanged,
4066
+ onPicturesToAiConsentChange,
3966
4067
  pluginBundleUrl,
3967
4068
  register,
3968
4069
  registerBundleModules,