@ateam-ai-mobile/plugin-runtime 0.1.10 → 0.1.12

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
@@ -485,6 +485,16 @@ interface VisualCaptureOptions {
485
485
  signal?: AbortSignal;
486
486
  timeoutMs?: number;
487
487
  }
488
+ interface VisualStartOptions extends StartOptions<VisualIntent> {
489
+ /**
490
+ * Which camera: 'back' (the default) or 'front', the selfie camera — its
491
+ * frames are mirrored like the view the user sees, so a box's left is the
492
+ * screen's left. A binary without the front camera REJECTS 'front' rather
493
+ * than reading the back camera; `camera.facing` in the snapshot says which
494
+ * one is actually running.
495
+ */
496
+ facing?: 'front' | 'back';
497
+ }
488
498
  interface VisualDomain {
489
499
  /**
490
500
  * Cached read. Does NOT open the camera and does NOT take a picture.
@@ -497,7 +507,7 @@ interface VisualDomain {
497
507
  */
498
508
  getSnapshot(): Promise<VisualSnapshot>;
499
509
  /** Maintain visual state according to this intent. Not "open the camera". */
500
- start(options: StartOptions<VisualIntent>): Promise<StateSession>;
510
+ start(options: VisualStartOptions): Promise<StateSession>;
501
511
  /**
502
512
  * An intentional, one-shot, high-quality-ish acquisition. THROWS
503
513
  * DeviceBridgeError on failure — it is an operation, not a read.
@@ -1002,11 +1012,12 @@ type deviceState_VisualFrameQuality = VisualFrameQuality;
1002
1012
  type deviceState_VisualFrameRef = VisualFrameRef;
1003
1013
  type deviceState_VisualIntent = VisualIntent;
1004
1014
  type deviceState_VisualSnapshot = VisualSnapshot;
1015
+ type deviceState_VisualStartOptions = VisualStartOptions;
1005
1016
  declare const deviceState_explainCapability: typeof explainCapability;
1006
1017
  declare const deviceState_isActionable: typeof isActionable;
1007
1018
  declare const deviceState_neverObserved: typeof neverObserved;
1008
1019
  declare namespace deviceState {
1009
- export { type deviceState_ActivityDomain as ActivityDomain, type deviceState_ActivityIntent as ActivityIntent, type deviceState_ActivitySnapshot as ActivitySnapshot, type deviceState_AssertConforming as AssertConforming, type deviceState_AvailabilityState as AvailabilityState, type deviceState_CapabilityDomain as CapabilityDomain, type deviceState_CapabilityEvent as CapabilityEvent, type deviceState_CapabilitySnapshot as CapabilitySnapshot, type deviceState_CapabilityStatus as CapabilityStatus, type deviceState_Confidence as Confidence, type deviceState_ConfidenceLevel as ConfidenceLevel, type deviceState_ConformingEventName as ConformingEventName, type deviceState_ConnectivityDomain as ConnectivityDomain, type deviceState_ConnectivityEvent as ConnectivityEvent, type deviceState_ConnectivityIntent as ConnectivityIntent, type deviceState_ConnectivitySnapshot as ConnectivitySnapshot, type deviceState_DeviceBridgeDomain as DeviceBridgeDomain, deviceState_DeviceBridgeError as DeviceBridgeError, type deviceState_DeviceBridgeErrorCode as DeviceBridgeErrorCode, type deviceState_DeviceBridgeV2 as DeviceBridgeV2, type deviceState_DeviceContextDomain as DeviceContextDomain, type deviceState_DeviceContextSnapshot as DeviceContextSnapshot, type deviceState_DevicePlacement as DevicePlacement, type deviceState_DeviceState as DeviceState, type deviceState_DeviceToolContextV2Extension as DeviceToolContextV2Extension, type deviceState_EnvironmentDomain as EnvironmentDomain, type deviceState_EnvironmentEvent as EnvironmentEvent, type deviceState_EnvironmentIntent as EnvironmentIntent, type deviceState_EnvironmentSnapshot as EnvironmentSnapshot, type deviceState_Freshness as Freshness, type deviceState_FreshnessState as FreshnessState, type deviceState_HumanActivity as HumanActivity, type deviceState_InteractionDomain as InteractionDomain, type deviceState_InteractionEvent as InteractionEvent, type deviceState_InteractionSnapshot as InteractionSnapshot, type deviceState_MediaHandle as MediaHandle, type PermissionState$1 as PermissionState, type deviceState_PluginPropsV2Extension as PluginPropsV2Extension, type deviceState_RestrictionState as RestrictionState, type deviceState_SpatialDomain as SpatialDomain, type deviceState_SpatialEvent as SpatialEvent, type deviceState_SpatialIntent as SpatialIntent, type deviceState_SpatialPoint as SpatialPoint, type deviceState_SpatialSnapshot as SpatialSnapshot, type deviceState_SpatialStateEvent as SpatialStateEvent, type deviceState_StartOptions as StartOptions, type deviceState_StateDomainDeclaration as StateDomainDeclaration, type deviceState_StateEvent as StateEvent, type deviceState_StateListener as StateListener, type deviceState_StateQuality as StateQuality, type deviceState_StateSession as StateSession, type deviceState_StatefulDomain as StatefulDomain, type deviceState_Subscription as Subscription, type deviceState_SupportState as SupportState, type deviceState_VisualCaptureOptions as VisualCaptureOptions, type deviceState_VisualCaptureResult as VisualCaptureResult, type deviceState_VisualDomain as VisualDomain, type deviceState_VisualFrameQuality as VisualFrameQuality, type deviceState_VisualFrameRef as VisualFrameRef, type deviceState_VisualIntent as VisualIntent, type deviceState_VisualSnapshot as VisualSnapshot, deviceState_explainCapability as explainCapability, deviceState_isActionable as isActionable, deviceState_neverObserved as neverObserved };
1020
+ export { type deviceState_ActivityDomain as ActivityDomain, type deviceState_ActivityIntent as ActivityIntent, type deviceState_ActivitySnapshot as ActivitySnapshot, type deviceState_AssertConforming as AssertConforming, type deviceState_AvailabilityState as AvailabilityState, type deviceState_CapabilityDomain as CapabilityDomain, type deviceState_CapabilityEvent as CapabilityEvent, type deviceState_CapabilitySnapshot as CapabilitySnapshot, type deviceState_CapabilityStatus as CapabilityStatus, type deviceState_Confidence as Confidence, type deviceState_ConfidenceLevel as ConfidenceLevel, type deviceState_ConformingEventName as ConformingEventName, type deviceState_ConnectivityDomain as ConnectivityDomain, type deviceState_ConnectivityEvent as ConnectivityEvent, type deviceState_ConnectivityIntent as ConnectivityIntent, type deviceState_ConnectivitySnapshot as ConnectivitySnapshot, type deviceState_DeviceBridgeDomain as DeviceBridgeDomain, deviceState_DeviceBridgeError as DeviceBridgeError, type deviceState_DeviceBridgeErrorCode as DeviceBridgeErrorCode, type deviceState_DeviceBridgeV2 as DeviceBridgeV2, type deviceState_DeviceContextDomain as DeviceContextDomain, type deviceState_DeviceContextSnapshot as DeviceContextSnapshot, type deviceState_DevicePlacement as DevicePlacement, type deviceState_DeviceState as DeviceState, type deviceState_DeviceToolContextV2Extension as DeviceToolContextV2Extension, type deviceState_EnvironmentDomain as EnvironmentDomain, type deviceState_EnvironmentEvent as EnvironmentEvent, type deviceState_EnvironmentIntent as EnvironmentIntent, type deviceState_EnvironmentSnapshot as EnvironmentSnapshot, type deviceState_Freshness as Freshness, type deviceState_FreshnessState as FreshnessState, type deviceState_HumanActivity as HumanActivity, type deviceState_InteractionDomain as InteractionDomain, type deviceState_InteractionEvent as InteractionEvent, type deviceState_InteractionSnapshot as InteractionSnapshot, type deviceState_MediaHandle as MediaHandle, type PermissionState$1 as PermissionState, type deviceState_PluginPropsV2Extension as PluginPropsV2Extension, type deviceState_RestrictionState as RestrictionState, type deviceState_SpatialDomain as SpatialDomain, type deviceState_SpatialEvent as SpatialEvent, type deviceState_SpatialIntent as SpatialIntent, type deviceState_SpatialPoint as SpatialPoint, type deviceState_SpatialSnapshot as SpatialSnapshot, type deviceState_SpatialStateEvent as SpatialStateEvent, type deviceState_StartOptions as StartOptions, type deviceState_StateDomainDeclaration as StateDomainDeclaration, type deviceState_StateEvent as StateEvent, type deviceState_StateListener as StateListener, type deviceState_StateQuality as StateQuality, type deviceState_StateSession as StateSession, type deviceState_StatefulDomain as StatefulDomain, type deviceState_Subscription as Subscription, type deviceState_SupportState as SupportState, type deviceState_VisualCaptureOptions as VisualCaptureOptions, type deviceState_VisualCaptureResult as VisualCaptureResult, type deviceState_VisualDomain as VisualDomain, type deviceState_VisualFrameQuality as VisualFrameQuality, type deviceState_VisualFrameRef as VisualFrameRef, type deviceState_VisualIntent as VisualIntent, type deviceState_VisualSnapshot as VisualSnapshot, type deviceState_VisualStartOptions as VisualStartOptions, deviceState_explainCapability as explainCapability, deviceState_isActionable as isActionable, deviceState_neverObserved as neverObserved };
1010
1021
  }
1011
1022
 
1012
1023
  /**
@@ -1217,11 +1228,13 @@ interface VoiceAPI {
1217
1228
  prompt(input: string): void;
1218
1229
  /**
1219
1230
  * Stream a silent OBSERVATION into the session — tell the model something
1220
- * without asking it to speak (a `system` conversation item). Cheap and
1221
- * high-frequency (safe once or twice a second): this is the channel for what
1222
- * the camera sees while the user walks. The model answers with the
1223
- * observations in hand the next time it takes a turn (user VAD, or prompt()) —
1224
- * an observation never triggers a turn by itself. Throws if not connected.
1231
+ * without asking it to speak (a `system` conversation item): the channel for
1232
+ * what the camera sees while the user walks. Limited, because every item stays
1233
+ * in the model's context for the call: 2 a second (bursts of 4) and 2000
1234
+ * characters each; over the limit it THROWS, so send only material changes.
1235
+ * The model answers with the observations in hand the next time it takes a
1236
+ * turn (user VAD, or prompt()) — an observation never triggers a turn by
1237
+ * itself. Throws if not connected.
1225
1238
  */
1226
1239
  observe(text: string): void;
1227
1240
  /** Point-in-time session state. */
@@ -2208,14 +2221,24 @@ declare const PluginSDK: {
2208
2221
 
2209
2222
  /** Host DI: the app supplies the engines it has. Called once at startup. */
2210
2223
  declare function setDeviceStateProvider(state: Partial<DeviceState>): void;
2224
+ /**
2225
+ * Release `holder`'s holds — in every domain, or in every domain NOT in `keep`
2226
+ * (a surface whose grants shrank keeps only what it may still use) — and stop
2227
+ * each engine that no one holds any more.
2228
+ */
2229
+ declare function releaseDeviceStateHolds(holder: string, keep?: readonly DeviceBridgeDomain[]): Promise<void>;
2230
+ /** Who holds what — for diagnostics and tests. */
2231
+ declare function deviceStateHolders(domain: DeviceBridgeDomain): string[];
2211
2232
  /**
2212
2233
  * The `deviceState` a plugin receives, gated by what it declared.
2213
2234
  *
2214
2235
  * Every domain is always present — a plugin can call any of the eight without
2215
2236
  * an existence check. What differs is whether it answers with data, or with
2216
- * an explicit "I know nothing" and a reason.
2237
+ * an explicit "I know nothing" and a reason. `holder` names who a start() holds
2238
+ * the session for (see Holds above); a caller with no lifetime of its own passes
2239
+ * the plugin id.
2217
2240
  */
2218
- declare function gateDeviceState(declared?: readonly DeviceBridgeDomain[]): DeviceState;
2241
+ declare function gateDeviceState(declared: readonly DeviceBridgeDomain[] | undefined, holder: string): DeviceState;
2219
2242
  /** Which domains this build can actually answer — for diagnostics. */
2220
2243
  declare function implementedStateDomains(): DeviceBridgeDomain[];
2221
2244
 
@@ -2363,7 +2386,7 @@ interface PluginGrants {
2363
2386
  declare function resolvePluginGrants(src: PluginRuntimeSource): PluginGrants;
2364
2387
  /** Turn a plugin's grants into the gated { device, native, deviceState, voice } it
2365
2388
  * receives on every rendered surface. */
2366
- declare function resolvePluginRuntimeProps(src: PluginRuntimeSource): PluginRuntimeProps;
2389
+ declare function resolvePluginRuntimeProps(src: PluginRuntimeSource, holder?: string): PluginRuntimeProps;
2367
2390
 
2368
2391
  interface DeviceToolSummary {
2369
2392
  name: string;
@@ -2393,7 +2416,8 @@ declare function setDeviceToolContextProvider(fn: (pluginId: string, capabilitie
2393
2416
  * Re-registering the same plugin (bundle reload) replaces its own entries.
2394
2417
  */
2395
2418
  declare function registerDeviceTools(pluginId: string, tools: DeviceToolDefinition[], capabilities?: NativeCapabilities$1, stateDomains?: DeviceBridgeDomain[]): string[];
2396
- /** Drop every tool owned by a plugin (bundle eviction / plugin revoked). */
2419
+ /** Drop every tool owned by a plugin (bundle eviction / plugin revoked), and the
2420
+ * sessions its tools started. */
2397
2421
  declare function unregisterDeviceTools(pluginId: string): void;
2398
2422
  /** Is `name` registered — and, given `pluginId`, registered BY that plugin?
2399
2423
  * (A clean voice call only lets its owner's own tools run.) */
@@ -2968,6 +2992,8 @@ interface UsePluginResult {
2968
2992
  }
2969
2993
  declare function usePlugin(pluginId: string, manifest: PluginManifestLike): UsePluginResult;
2970
2994
 
2995
+ declare function usePluginRuntimeProps(src: PluginRuntimeSource, deps: readonly unknown[]): PluginRuntimeProps;
2996
+
2971
2997
  interface RemotePlugin {
2972
2998
  id: string;
2973
2999
  name: string;
@@ -3306,4 +3332,4 @@ declare function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest
3306
3332
 
3307
3333
  declare function SurfaceDispatcher(): react_jsx_runtime.JSX.Element;
3308
3334
 
3309
- export { ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, 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 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, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginTheme, useRemotePlugins, useSurfaceStore };
3335
+ export { ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, 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, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseDeviceStateHolds, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
package/dist/index.d.ts CHANGED
@@ -485,6 +485,16 @@ interface VisualCaptureOptions {
485
485
  signal?: AbortSignal;
486
486
  timeoutMs?: number;
487
487
  }
488
+ interface VisualStartOptions extends StartOptions<VisualIntent> {
489
+ /**
490
+ * Which camera: 'back' (the default) or 'front', the selfie camera — its
491
+ * frames are mirrored like the view the user sees, so a box's left is the
492
+ * screen's left. A binary without the front camera REJECTS 'front' rather
493
+ * than reading the back camera; `camera.facing` in the snapshot says which
494
+ * one is actually running.
495
+ */
496
+ facing?: 'front' | 'back';
497
+ }
488
498
  interface VisualDomain {
489
499
  /**
490
500
  * Cached read. Does NOT open the camera and does NOT take a picture.
@@ -497,7 +507,7 @@ interface VisualDomain {
497
507
  */
498
508
  getSnapshot(): Promise<VisualSnapshot>;
499
509
  /** Maintain visual state according to this intent. Not "open the camera". */
500
- start(options: StartOptions<VisualIntent>): Promise<StateSession>;
510
+ start(options: VisualStartOptions): Promise<StateSession>;
501
511
  /**
502
512
  * An intentional, one-shot, high-quality-ish acquisition. THROWS
503
513
  * DeviceBridgeError on failure — it is an operation, not a read.
@@ -1002,11 +1012,12 @@ type deviceState_VisualFrameQuality = VisualFrameQuality;
1002
1012
  type deviceState_VisualFrameRef = VisualFrameRef;
1003
1013
  type deviceState_VisualIntent = VisualIntent;
1004
1014
  type deviceState_VisualSnapshot = VisualSnapshot;
1015
+ type deviceState_VisualStartOptions = VisualStartOptions;
1005
1016
  declare const deviceState_explainCapability: typeof explainCapability;
1006
1017
  declare const deviceState_isActionable: typeof isActionable;
1007
1018
  declare const deviceState_neverObserved: typeof neverObserved;
1008
1019
  declare namespace deviceState {
1009
- export { type deviceState_ActivityDomain as ActivityDomain, type deviceState_ActivityIntent as ActivityIntent, type deviceState_ActivitySnapshot as ActivitySnapshot, type deviceState_AssertConforming as AssertConforming, type deviceState_AvailabilityState as AvailabilityState, type deviceState_CapabilityDomain as CapabilityDomain, type deviceState_CapabilityEvent as CapabilityEvent, type deviceState_CapabilitySnapshot as CapabilitySnapshot, type deviceState_CapabilityStatus as CapabilityStatus, type deviceState_Confidence as Confidence, type deviceState_ConfidenceLevel as ConfidenceLevel, type deviceState_ConformingEventName as ConformingEventName, type deviceState_ConnectivityDomain as ConnectivityDomain, type deviceState_ConnectivityEvent as ConnectivityEvent, type deviceState_ConnectivityIntent as ConnectivityIntent, type deviceState_ConnectivitySnapshot as ConnectivitySnapshot, type deviceState_DeviceBridgeDomain as DeviceBridgeDomain, deviceState_DeviceBridgeError as DeviceBridgeError, type deviceState_DeviceBridgeErrorCode as DeviceBridgeErrorCode, type deviceState_DeviceBridgeV2 as DeviceBridgeV2, type deviceState_DeviceContextDomain as DeviceContextDomain, type deviceState_DeviceContextSnapshot as DeviceContextSnapshot, type deviceState_DevicePlacement as DevicePlacement, type deviceState_DeviceState as DeviceState, type deviceState_DeviceToolContextV2Extension as DeviceToolContextV2Extension, type deviceState_EnvironmentDomain as EnvironmentDomain, type deviceState_EnvironmentEvent as EnvironmentEvent, type deviceState_EnvironmentIntent as EnvironmentIntent, type deviceState_EnvironmentSnapshot as EnvironmentSnapshot, type deviceState_Freshness as Freshness, type deviceState_FreshnessState as FreshnessState, type deviceState_HumanActivity as HumanActivity, type deviceState_InteractionDomain as InteractionDomain, type deviceState_InteractionEvent as InteractionEvent, type deviceState_InteractionSnapshot as InteractionSnapshot, type deviceState_MediaHandle as MediaHandle, type PermissionState$1 as PermissionState, type deviceState_PluginPropsV2Extension as PluginPropsV2Extension, type deviceState_RestrictionState as RestrictionState, type deviceState_SpatialDomain as SpatialDomain, type deviceState_SpatialEvent as SpatialEvent, type deviceState_SpatialIntent as SpatialIntent, type deviceState_SpatialPoint as SpatialPoint, type deviceState_SpatialSnapshot as SpatialSnapshot, type deviceState_SpatialStateEvent as SpatialStateEvent, type deviceState_StartOptions as StartOptions, type deviceState_StateDomainDeclaration as StateDomainDeclaration, type deviceState_StateEvent as StateEvent, type deviceState_StateListener as StateListener, type deviceState_StateQuality as StateQuality, type deviceState_StateSession as StateSession, type deviceState_StatefulDomain as StatefulDomain, type deviceState_Subscription as Subscription, type deviceState_SupportState as SupportState, type deviceState_VisualCaptureOptions as VisualCaptureOptions, type deviceState_VisualCaptureResult as VisualCaptureResult, type deviceState_VisualDomain as VisualDomain, type deviceState_VisualFrameQuality as VisualFrameQuality, type deviceState_VisualFrameRef as VisualFrameRef, type deviceState_VisualIntent as VisualIntent, type deviceState_VisualSnapshot as VisualSnapshot, deviceState_explainCapability as explainCapability, deviceState_isActionable as isActionable, deviceState_neverObserved as neverObserved };
1020
+ export { type deviceState_ActivityDomain as ActivityDomain, type deviceState_ActivityIntent as ActivityIntent, type deviceState_ActivitySnapshot as ActivitySnapshot, type deviceState_AssertConforming as AssertConforming, type deviceState_AvailabilityState as AvailabilityState, type deviceState_CapabilityDomain as CapabilityDomain, type deviceState_CapabilityEvent as CapabilityEvent, type deviceState_CapabilitySnapshot as CapabilitySnapshot, type deviceState_CapabilityStatus as CapabilityStatus, type deviceState_Confidence as Confidence, type deviceState_ConfidenceLevel as ConfidenceLevel, type deviceState_ConformingEventName as ConformingEventName, type deviceState_ConnectivityDomain as ConnectivityDomain, type deviceState_ConnectivityEvent as ConnectivityEvent, type deviceState_ConnectivityIntent as ConnectivityIntent, type deviceState_ConnectivitySnapshot as ConnectivitySnapshot, type deviceState_DeviceBridgeDomain as DeviceBridgeDomain, deviceState_DeviceBridgeError as DeviceBridgeError, type deviceState_DeviceBridgeErrorCode as DeviceBridgeErrorCode, type deviceState_DeviceBridgeV2 as DeviceBridgeV2, type deviceState_DeviceContextDomain as DeviceContextDomain, type deviceState_DeviceContextSnapshot as DeviceContextSnapshot, type deviceState_DevicePlacement as DevicePlacement, type deviceState_DeviceState as DeviceState, type deviceState_DeviceToolContextV2Extension as DeviceToolContextV2Extension, type deviceState_EnvironmentDomain as EnvironmentDomain, type deviceState_EnvironmentEvent as EnvironmentEvent, type deviceState_EnvironmentIntent as EnvironmentIntent, type deviceState_EnvironmentSnapshot as EnvironmentSnapshot, type deviceState_Freshness as Freshness, type deviceState_FreshnessState as FreshnessState, type deviceState_HumanActivity as HumanActivity, type deviceState_InteractionDomain as InteractionDomain, type deviceState_InteractionEvent as InteractionEvent, type deviceState_InteractionSnapshot as InteractionSnapshot, type deviceState_MediaHandle as MediaHandle, type PermissionState$1 as PermissionState, type deviceState_PluginPropsV2Extension as PluginPropsV2Extension, type deviceState_RestrictionState as RestrictionState, type deviceState_SpatialDomain as SpatialDomain, type deviceState_SpatialEvent as SpatialEvent, type deviceState_SpatialIntent as SpatialIntent, type deviceState_SpatialPoint as SpatialPoint, type deviceState_SpatialSnapshot as SpatialSnapshot, type deviceState_SpatialStateEvent as SpatialStateEvent, type deviceState_StartOptions as StartOptions, type deviceState_StateDomainDeclaration as StateDomainDeclaration, type deviceState_StateEvent as StateEvent, type deviceState_StateListener as StateListener, type deviceState_StateQuality as StateQuality, type deviceState_StateSession as StateSession, type deviceState_StatefulDomain as StatefulDomain, type deviceState_Subscription as Subscription, type deviceState_SupportState as SupportState, type deviceState_VisualCaptureOptions as VisualCaptureOptions, type deviceState_VisualCaptureResult as VisualCaptureResult, type deviceState_VisualDomain as VisualDomain, type deviceState_VisualFrameQuality as VisualFrameQuality, type deviceState_VisualFrameRef as VisualFrameRef, type deviceState_VisualIntent as VisualIntent, type deviceState_VisualSnapshot as VisualSnapshot, type deviceState_VisualStartOptions as VisualStartOptions, deviceState_explainCapability as explainCapability, deviceState_isActionable as isActionable, deviceState_neverObserved as neverObserved };
1010
1021
  }
1011
1022
 
1012
1023
  /**
@@ -1217,11 +1228,13 @@ interface VoiceAPI {
1217
1228
  prompt(input: string): void;
1218
1229
  /**
1219
1230
  * Stream a silent OBSERVATION into the session — tell the model something
1220
- * without asking it to speak (a `system` conversation item). Cheap and
1221
- * high-frequency (safe once or twice a second): this is the channel for what
1222
- * the camera sees while the user walks. The model answers with the
1223
- * observations in hand the next time it takes a turn (user VAD, or prompt()) —
1224
- * an observation never triggers a turn by itself. Throws if not connected.
1231
+ * without asking it to speak (a `system` conversation item): the channel for
1232
+ * what the camera sees while the user walks. Limited, because every item stays
1233
+ * in the model's context for the call: 2 a second (bursts of 4) and 2000
1234
+ * characters each; over the limit it THROWS, so send only material changes.
1235
+ * The model answers with the observations in hand the next time it takes a
1236
+ * turn (user VAD, or prompt()) — an observation never triggers a turn by
1237
+ * itself. Throws if not connected.
1225
1238
  */
1226
1239
  observe(text: string): void;
1227
1240
  /** Point-in-time session state. */
@@ -2208,14 +2221,24 @@ declare const PluginSDK: {
2208
2221
 
2209
2222
  /** Host DI: the app supplies the engines it has. Called once at startup. */
2210
2223
  declare function setDeviceStateProvider(state: Partial<DeviceState>): void;
2224
+ /**
2225
+ * Release `holder`'s holds — in every domain, or in every domain NOT in `keep`
2226
+ * (a surface whose grants shrank keeps only what it may still use) — and stop
2227
+ * each engine that no one holds any more.
2228
+ */
2229
+ declare function releaseDeviceStateHolds(holder: string, keep?: readonly DeviceBridgeDomain[]): Promise<void>;
2230
+ /** Who holds what — for diagnostics and tests. */
2231
+ declare function deviceStateHolders(domain: DeviceBridgeDomain): string[];
2211
2232
  /**
2212
2233
  * The `deviceState` a plugin receives, gated by what it declared.
2213
2234
  *
2214
2235
  * Every domain is always present — a plugin can call any of the eight without
2215
2236
  * an existence check. What differs is whether it answers with data, or with
2216
- * an explicit "I know nothing" and a reason.
2237
+ * an explicit "I know nothing" and a reason. `holder` names who a start() holds
2238
+ * the session for (see Holds above); a caller with no lifetime of its own passes
2239
+ * the plugin id.
2217
2240
  */
2218
- declare function gateDeviceState(declared?: readonly DeviceBridgeDomain[]): DeviceState;
2241
+ declare function gateDeviceState(declared: readonly DeviceBridgeDomain[] | undefined, holder: string): DeviceState;
2219
2242
  /** Which domains this build can actually answer — for diagnostics. */
2220
2243
  declare function implementedStateDomains(): DeviceBridgeDomain[];
2221
2244
 
@@ -2363,7 +2386,7 @@ interface PluginGrants {
2363
2386
  declare function resolvePluginGrants(src: PluginRuntimeSource): PluginGrants;
2364
2387
  /** Turn a plugin's grants into the gated { device, native, deviceState, voice } it
2365
2388
  * receives on every rendered surface. */
2366
- declare function resolvePluginRuntimeProps(src: PluginRuntimeSource): PluginRuntimeProps;
2389
+ declare function resolvePluginRuntimeProps(src: PluginRuntimeSource, holder?: string): PluginRuntimeProps;
2367
2390
 
2368
2391
  interface DeviceToolSummary {
2369
2392
  name: string;
@@ -2393,7 +2416,8 @@ declare function setDeviceToolContextProvider(fn: (pluginId: string, capabilitie
2393
2416
  * Re-registering the same plugin (bundle reload) replaces its own entries.
2394
2417
  */
2395
2418
  declare function registerDeviceTools(pluginId: string, tools: DeviceToolDefinition[], capabilities?: NativeCapabilities$1, stateDomains?: DeviceBridgeDomain[]): string[];
2396
- /** Drop every tool owned by a plugin (bundle eviction / plugin revoked). */
2419
+ /** Drop every tool owned by a plugin (bundle eviction / plugin revoked), and the
2420
+ * sessions its tools started. */
2397
2421
  declare function unregisterDeviceTools(pluginId: string): void;
2398
2422
  /** Is `name` registered — and, given `pluginId`, registered BY that plugin?
2399
2423
  * (A clean voice call only lets its owner's own tools run.) */
@@ -2968,6 +2992,8 @@ interface UsePluginResult {
2968
2992
  }
2969
2993
  declare function usePlugin(pluginId: string, manifest: PluginManifestLike): UsePluginResult;
2970
2994
 
2995
+ declare function usePluginRuntimeProps(src: PluginRuntimeSource, deps: readonly unknown[]): PluginRuntimeProps;
2996
+
2971
2997
  interface RemotePlugin {
2972
2998
  id: string;
2973
2999
  name: string;
@@ -3306,4 +3332,4 @@ declare function isInlineSurface(m: SurfaceManifest): m is InlineSurfaceManifest
3306
3332
 
3307
3333
  declare function SurfaceDispatcher(): react_jsx_runtime.JSX.Element;
3308
3334
 
3309
- export { ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, 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 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, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginTheme, useRemotePlugins, useSurfaceStore };
3335
+ export { ActionButton, type ActivitySnapshot, AdaOrb, type AdaOrbState, 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, bundleManager, callDeviceTool, clearDeviceTools, createNativeBridge, deviceStateHolders, deviceState as deviceStateV2, deviceToolsActionForSession, ensureDeviceToolsLoaded, explainCapability, gateDeviceState, gatePluginNative, gateVoice, getCameraPreviewProvider, getHaptics, getNativeBundleHash, getNativeBundleUrl, getNativeComponentId, getPlugin, getPluginNative, handleServerDeviceToolCall, hasDeviceTool, implementedStateDomains, implementedVoice, isActionable, isDeviceToolCommand, isInlineSurface, isMountSurface, listDeviceTools, listPlugins, nativePluginRegistry, neverObserved, pluginBundleUrl, register, registerBundleModules, registerDeviceTools, registerNativePlugin, registerPlatformDeviceTools, registerService, registerTools, releaseDeviceStateHolds, resetDeviceToolLoader, resolvePluginGrants, resolvePluginRuntimeProps, resolvePluginUrl, setBundleStorage, setCameraPreviewProvider, setDeviceStateProvider, setDeviceToolContextProvider, setDeviceToolResultPoster, setHapticsProvider, setPluginNativeProvider, setPluginThemeColors, setVoiceProvider, supportsNative, supportsWebView, syncDeviceToolsForSession, unregisterDeviceTools, unregisterNativePlugin, useApi, useNativeBridge, usePlugin, usePluginRuntimeProps, usePluginTheme, useRemotePlugins, useSurfaceStore };
package/dist/index.js CHANGED
@@ -860,7 +860,57 @@ function denial(domain, why) {
860
860
  function setDeviceStateProvider(state) {
861
861
  _provider = state || {};
862
862
  }
863
- function gateDeviceState(declared) {
863
+ function holdersOf(domain) {
864
+ let s = holds.get(domain);
865
+ if (!s) {
866
+ s = /* @__PURE__ */ new Set();
867
+ holds.set(domain, s);
868
+ }
869
+ return s;
870
+ }
871
+ function withHolds(domain, engine, holder) {
872
+ if (!engine || typeof engine.start !== "function" || typeof engine.stop !== "function") return engine;
873
+ return Object.assign(Object.create(engine), {
874
+ async start(options) {
875
+ const s = holdersOf(domain);
876
+ const fresh = !s.has(holder);
877
+ s.add(holder);
878
+ let result;
879
+ try {
880
+ result = await engine.start(options);
881
+ } catch (e) {
882
+ if (fresh && s.delete(holder) && s.size === 0) await stopQuietly(engine);
883
+ throw e;
884
+ }
885
+ if (!s.has(holder) && s.size === 0) await stopQuietly(engine);
886
+ return result;
887
+ },
888
+ async stop() {
889
+ const s = holdersOf(domain);
890
+ if (!s.has(holder)) return;
891
+ s.delete(holder);
892
+ if (s.size === 0) await engine.stop();
893
+ }
894
+ });
895
+ }
896
+ async function stopQuietly(engine) {
897
+ try {
898
+ await engine?.stop?.();
899
+ } catch {
900
+ }
901
+ }
902
+ async function releaseDeviceStateHolds(holder, keep = []) {
903
+ for (const [domain, s] of holds) {
904
+ if (keep.includes(domain)) continue;
905
+ if (!s.delete(holder) || s.size > 0) continue;
906
+ await stopQuietly(_provider[domain]);
907
+ }
908
+ }
909
+ function deviceStateHolders(domain) {
910
+ return [...holds.get(domain) || []];
911
+ }
912
+ function gateDeviceState(declared, holder) {
913
+ if (!holder) throw new Error("gateDeviceState: a holder is required \u2014 who would release a session it starts?");
864
914
  const allowed = new Set(declared || []);
865
915
  const out = {};
866
916
  for (const domain of ALL_DOMAINS) {
@@ -872,7 +922,7 @@ function gateDeviceState(declared) {
872
922
  continue;
873
923
  }
874
924
  const engine = _provider[domain];
875
- out[domain] = engine ?? deniedDomain(
925
+ out[domain] = engine ? withHolds(domain, engine, holder) : deniedDomain(
876
926
  domain,
877
927
  "no engine in this build \u2014 the native side does not exist yet. See docs/DEVICE_API_STATUS.md."
878
928
  );
@@ -895,7 +945,7 @@ function withoutSubscribe(state) {
895
945
  function implementedStateDomains() {
896
946
  return ALL_DOMAINS.filter((d) => !!_provider[d]);
897
947
  }
898
- var UNKNOWN_QUALITY, ALL_DOMAINS, _provider;
948
+ var UNKNOWN_QUALITY, ALL_DOMAINS, _provider, holds;
899
949
  var init_deviceStateHost = __esm({
900
950
  "src/deviceStateHost.ts"() {
901
951
  "use strict";
@@ -914,6 +964,7 @@ var init_deviceStateHost = __esm({
914
964
  "interaction"
915
965
  ];
916
966
  _provider = {};
967
+ holds = /* @__PURE__ */ new Map();
917
968
  }
918
969
  });
919
970
 
@@ -1016,10 +1067,10 @@ function resolvePluginGrants(src) {
1016
1067
  const stateDomains = trusted?.stateDomains ? [...trusted.stateDomains] : void 0;
1017
1068
  return { capabilities: mergeCaps(trusted), stateDomains };
1018
1069
  }
1019
- function resolvePluginRuntimeProps(src) {
1070
+ function resolvePluginRuntimeProps(src, holder = src.pluginId) {
1020
1071
  const { capabilities, stateDomains } = resolvePluginGrants(src);
1021
1072
  const native = gatePluginNative(getPluginNative(), capabilities, src.pluginId);
1022
- const deviceState = gateDeviceState(stateDomains);
1073
+ const deviceState = gateDeviceState(stateDomains, holder);
1023
1074
  const voice = gateVoice(!!capabilities?.voice, src.pluginId);
1024
1075
  return { device: native, native, deviceState, voice };
1025
1076
  }
@@ -1249,7 +1300,9 @@ function defaultContext(pluginId, capabilities, stateDomains) {
1249
1300
  return {
1250
1301
  bridge: createNativeBridge(pluginId),
1251
1302
  native: gatePluginNative(getPluginNative(), capabilities, pluginId),
1252
- deviceState: gateDeviceState(stateDomains)
1303
+ // A tool call has no lifetime of its own: what it starts is held for the
1304
+ // plugin's tools, and released when the plugin's tools are unregistered.
1305
+ deviceState: gateDeviceState(stateDomains, toolHolder(pluginId))
1253
1306
  };
1254
1307
  }
1255
1308
  function registerDeviceTools(pluginId, tools, capabilities, stateDomains) {
@@ -1274,10 +1327,14 @@ function registerDeviceTools(pluginId, tools, capabilities, stateDomains) {
1274
1327
  }
1275
1328
  return accepted;
1276
1329
  }
1330
+ function toolHolder(pluginId) {
1331
+ return `tools:${pluginId}`;
1332
+ }
1277
1333
  function unregisterDeviceTools(pluginId) {
1278
1334
  for (const [name, entry] of registry.entries()) {
1279
1335
  if (entry.pluginId === pluginId) registry.delete(name);
1280
1336
  }
1337
+ void releaseDeviceStateHolds(toolHolder(pluginId));
1281
1338
  }
1282
1339
  function hasDeviceTool(name, pluginId) {
1283
1340
  const entry = registry.get(name);
@@ -3301,6 +3358,7 @@ __export(index_exports, {
3301
3358
  callDeviceTool: () => callDeviceTool,
3302
3359
  clearDeviceTools: () => clearDeviceTools,
3303
3360
  createNativeBridge: () => createNativeBridge,
3361
+ deviceStateHolders: () => deviceStateHolders,
3304
3362
  deviceStateV2: () => device_state_exports,
3305
3363
  deviceToolsActionForSession: () => deviceToolsActionForSession,
3306
3364
  ensureDeviceToolsLoaded: () => ensureDeviceToolsLoaded,
@@ -3335,6 +3393,7 @@ __export(index_exports, {
3335
3393
  registerPlatformDeviceTools: () => registerPlatformDeviceTools,
3336
3394
  registerService: () => registerService,
3337
3395
  registerTools: () => registerTools,
3396
+ releaseDeviceStateHolds: () => releaseDeviceStateHolds,
3338
3397
  resetDeviceToolLoader: () => resetDeviceToolLoader,
3339
3398
  resolvePluginGrants: () => resolvePluginGrants,
3340
3399
  resolvePluginRuntimeProps: () => resolvePluginRuntimeProps,
@@ -3356,6 +3415,7 @@ __export(index_exports, {
3356
3415
  useApi: () => useApi,
3357
3416
  useNativeBridge: () => useNativeBridge,
3358
3417
  usePlugin: () => usePlugin,
3418
+ usePluginRuntimeProps: () => usePluginRuntimeProps,
3359
3419
  usePluginTheme: () => usePluginTheme,
3360
3420
  useRemotePlugins: () => useRemotePlugins,
3361
3421
  useSurfaceStore: () => useSurfaceStore
@@ -3589,15 +3649,38 @@ function usePlugin(pluginId, manifest) {
3589
3649
  return { plugin, loading, error, bundleMissing };
3590
3650
  }
3591
3651
 
3592
- // src/hooks/useRemotePlugins.ts
3652
+ // src/hooks/usePluginRuntimeProps.ts
3593
3653
  var import_react12 = require("react");
3654
+ init_pluginRuntime();
3655
+ init_deviceStateHost();
3656
+ var mounts = 0;
3657
+ function usePluginRuntimeProps(src, deps) {
3658
+ const holderRef = (0, import_react12.useRef)(null);
3659
+ if (holderRef.current?.pluginId !== src.pluginId) {
3660
+ holderRef.current = { pluginId: src.pluginId, holder: `${src.pluginId}#${++mounts}` };
3661
+ }
3662
+ const holder = holderRef.current.holder;
3663
+ const props = (0, import_react12.useMemo)(() => resolvePluginRuntimeProps(src, holder), [...deps, holder]);
3664
+ const granted = (0, import_react12.useMemo)(() => resolvePluginGrants(src).stateDomains ?? [], deps);
3665
+ (0, import_react12.useEffect)(() => () => {
3666
+ void releaseDeviceStateHolds(holder);
3667
+ }, [holder]);
3668
+ const grantedKey = granted.join(",");
3669
+ (0, import_react12.useEffect)(() => {
3670
+ void releaseDeviceStateHolds(holder, granted);
3671
+ }, [holder, grantedKey]);
3672
+ return props;
3673
+ }
3674
+
3675
+ // src/hooks/useRemotePlugins.ts
3676
+ var import_react13 = require("react");
3594
3677
  var import_core11 = require("@ateam-ai-mobile/core");
3595
3678
  function useRemotePlugins(solutionId) {
3596
- const [plugins, setPlugins] = (0, import_react12.useState)([]);
3597
- const [loading, setLoading] = (0, import_react12.useState)(true);
3598
- const [refreshing, setRefreshing] = (0, import_react12.useState)(false);
3599
- const [error, setError] = (0, import_react12.useState)(null);
3600
- const fetchRemotePlugins = (0, import_react12.useCallback)(async () => {
3679
+ const [plugins, setPlugins] = (0, import_react13.useState)([]);
3680
+ const [loading, setLoading] = (0, import_react13.useState)(true);
3681
+ const [refreshing, setRefreshing] = (0, import_react13.useState)(false);
3682
+ const [error, setError] = (0, import_react13.useState)(null);
3683
+ const fetchRemotePlugins = (0, import_react13.useCallback)(async () => {
3601
3684
  try {
3602
3685
  setError(null);
3603
3686
  const targetSolutionId = solutionId || "current";
@@ -3642,11 +3725,11 @@ function useRemotePlugins(solutionId) {
3642
3725
  setRefreshing(false);
3643
3726
  }
3644
3727
  }, [solutionId]);
3645
- const refresh = (0, import_react12.useCallback)(async () => {
3728
+ const refresh = (0, import_react13.useCallback)(async () => {
3646
3729
  setRefreshing(true);
3647
3730
  await fetchRemotePlugins();
3648
3731
  }, [fetchRemotePlugins]);
3649
- (0, import_react12.useEffect)(() => {
3732
+ (0, import_react13.useEffect)(() => {
3650
3733
  setLoading(true);
3651
3734
  fetchRemotePlugins();
3652
3735
  }, [fetchRemotePlugins]);
@@ -3709,6 +3792,7 @@ init_SurfaceDispatcher();
3709
3792
  callDeviceTool,
3710
3793
  clearDeviceTools,
3711
3794
  createNativeBridge,
3795
+ deviceStateHolders,
3712
3796
  deviceStateV2,
3713
3797
  deviceToolsActionForSession,
3714
3798
  ensureDeviceToolsLoaded,
@@ -3743,6 +3827,7 @@ init_SurfaceDispatcher();
3743
3827
  registerPlatformDeviceTools,
3744
3828
  registerService,
3745
3829
  registerTools,
3830
+ releaseDeviceStateHolds,
3746
3831
  resetDeviceToolLoader,
3747
3832
  resolvePluginGrants,
3748
3833
  resolvePluginRuntimeProps,
@@ -3764,6 +3849,7 @@ init_SurfaceDispatcher();
3764
3849
  useApi,
3765
3850
  useNativeBridge,
3766
3851
  usePlugin,
3852
+ usePluginRuntimeProps,
3767
3853
  usePluginTheme,
3768
3854
  useRemotePlugins,
3769
3855
  useSurfaceStore