@ateam-ai-mobile/plugin-runtime 0.1.20 → 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/{chunk-56Z2X5ZB.mjs → chunk-RNA6X65P.mjs} +211 -2
- package/dist/chunk-RNA6X65P.mjs.map +1 -0
- package/dist/index.d.mts +129 -1
- package/dist/index.d.ts +129 -1
- package/dist/index.js +242 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +26 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{loader-3PQLHEEW.mjs → loader-GGJ5YO25.mjs} +2 -2
- package/package.json +2 -2
- package/src/aiLiveHost.ts +200 -0
- package/src/hooks/usePluginRuntimeProps.ts +3 -0
- package/src/host.ts +51 -0
- package/src/index.ts +15 -0
- package/src/pluginRuntime.ts +10 -1
- package/src/sdk/aiLive.ts +111 -0
- package/src/sdk/index.ts +12 -0
- package/src/sdk/types.ts +24 -5
- package/dist/chunk-56Z2X5ZB.mjs.map +0 -1
- /package/dist/{loader-3PQLHEEW.mjs.map → loader-GGJ5YO25.mjs.map} +0 -0
|
@@ -141,6 +141,7 @@ import { apiFetchRaw, getTenant as getTenant2 } from "@ateam-ai-mobile/core";
|
|
|
141
141
|
// src/sdk/index.ts
|
|
142
142
|
var sdk_exports = {};
|
|
143
143
|
__export(sdk_exports, {
|
|
144
|
+
AI_LIVE_IDLE: () => AI_LIVE_IDLE,
|
|
144
145
|
ActionButton: () => ActionButton,
|
|
145
146
|
ActivityIndicator: () => ActivityIndicator,
|
|
146
147
|
Animated: () => Animated,
|
|
@@ -213,6 +214,16 @@ function registerService(id, config) {
|
|
|
213
214
|
// src/sdk/voice.ts
|
|
214
215
|
var PLATFORM_VOICE_CALLER = /* @__PURE__ */ Symbol("adas.voice.platform");
|
|
215
216
|
|
|
217
|
+
// src/sdk/aiLive.ts
|
|
218
|
+
var AI_LIVE_IDLE = Object.freeze({
|
|
219
|
+
state: "idle",
|
|
220
|
+
camera: null,
|
|
221
|
+
sent: 0,
|
|
222
|
+
skipped: 0,
|
|
223
|
+
lastEpisode: null,
|
|
224
|
+
lastError: null
|
|
225
|
+
});
|
|
226
|
+
|
|
216
227
|
// src/sdk/device-state.ts
|
|
217
228
|
var device_state_exports = {};
|
|
218
229
|
__export(device_state_exports, {
|
|
@@ -647,6 +658,35 @@ function setCameraPreviewProvider(Component) {
|
|
|
647
658
|
function getCameraPreviewProvider() {
|
|
648
659
|
return _cameraPreview;
|
|
649
660
|
}
|
|
661
|
+
var _picturesToAiConsent = null;
|
|
662
|
+
var _consentListeners = /* @__PURE__ */ new Set();
|
|
663
|
+
function setPicturesToAiConsentProvider(provider) {
|
|
664
|
+
_picturesToAiConsent = provider;
|
|
665
|
+
notifyPicturesToAiConsentChanged();
|
|
666
|
+
}
|
|
667
|
+
function notifyPicturesToAiConsentChanged() {
|
|
668
|
+
for (const cb of [..._consentListeners]) {
|
|
669
|
+
try {
|
|
670
|
+
cb();
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function onPicturesToAiConsentChange(cb) {
|
|
676
|
+
_consentListeners.add(cb);
|
|
677
|
+
return { unsubscribe: () => {
|
|
678
|
+
_consentListeners.delete(cb);
|
|
679
|
+
} };
|
|
680
|
+
}
|
|
681
|
+
function mayPicturesLeavePhone(declared) {
|
|
682
|
+
if (declared?.picturesToAi !== true) return false;
|
|
683
|
+
if (!_picturesToAiConsent) return false;
|
|
684
|
+
try {
|
|
685
|
+
return _picturesToAiConsent() === true;
|
|
686
|
+
} catch {
|
|
687
|
+
return false;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
650
690
|
var _nativeRegistry = /* @__PURE__ */ new Map();
|
|
651
691
|
function registerNativePlugin(id, plugin) {
|
|
652
692
|
_nativeRegistry.set(id, plugin);
|
|
@@ -3048,6 +3088,164 @@ function gateVoice(declared, pluginId) {
|
|
|
3048
3088
|
);
|
|
3049
3089
|
}
|
|
3050
3090
|
|
|
3091
|
+
// src/aiLiveHost.ts
|
|
3092
|
+
var _provider3 = null;
|
|
3093
|
+
var _screens = /* @__PURE__ */ new Map();
|
|
3094
|
+
function screenOf(holder) {
|
|
3095
|
+
let sc = _screens.get(holder);
|
|
3096
|
+
if (!sc) {
|
|
3097
|
+
sc = { closed: false, stops: 0, queue: Promise.resolve(), watch: null };
|
|
3098
|
+
_screens.set(holder, sc);
|
|
3099
|
+
}
|
|
3100
|
+
return sc;
|
|
3101
|
+
}
|
|
3102
|
+
function inTurn(sc, step) {
|
|
3103
|
+
const run = sc.queue.then(step, step);
|
|
3104
|
+
sc.queue = run.then(() => {
|
|
3105
|
+
}, () => {
|
|
3106
|
+
});
|
|
3107
|
+
return run;
|
|
3108
|
+
}
|
|
3109
|
+
var unwatch = (sc) => {
|
|
3110
|
+
sc.watch?.unsubscribe();
|
|
3111
|
+
sc.watch = null;
|
|
3112
|
+
};
|
|
3113
|
+
var STOPPED_BEFORE_START = "aiLive: stopped before it started: the screen stopped or closed while its start was waiting.";
|
|
3114
|
+
var SCREEN_CLOSED = "aiLive: this screen is closed; it cannot start sending.";
|
|
3115
|
+
var stopped = (msg) => Object.assign(new Error(msg), { code: "STOPPED" });
|
|
3116
|
+
var CONSENT_TAKEN_BACK = "Camera pictures to AI was turned off on this phone, so sending stopped.";
|
|
3117
|
+
function setAiLiveProvider(provider) {
|
|
3118
|
+
_provider3 = provider || null;
|
|
3119
|
+
}
|
|
3120
|
+
function denial2(why) {
|
|
3121
|
+
return Object.assign(new Error(`aiLive: ${why}`), { code: "RESTRICTED" });
|
|
3122
|
+
}
|
|
3123
|
+
function deniedAiLive(why) {
|
|
3124
|
+
const fail = () => {
|
|
3125
|
+
throw denial2(why);
|
|
3126
|
+
};
|
|
3127
|
+
return {
|
|
3128
|
+
async start() {
|
|
3129
|
+
return fail();
|
|
3130
|
+
},
|
|
3131
|
+
async stop() {
|
|
3132
|
+
},
|
|
3133
|
+
getSnapshot() {
|
|
3134
|
+
return { state: "error", camera: null, sent: 0, skipped: 0, lastEpisode: null, lastError: why };
|
|
3135
|
+
},
|
|
3136
|
+
onEpisode() {
|
|
3137
|
+
return fail();
|
|
3138
|
+
},
|
|
3139
|
+
subscribe() {
|
|
3140
|
+
return fail();
|
|
3141
|
+
}
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
var aiLiveCameraHolder = (holder) => `${holder}#aiLive`;
|
|
3145
|
+
function gateAiLive(capabilities, pluginId, holder, camera) {
|
|
3146
|
+
if (capabilities?.picturesToAi !== true) {
|
|
3147
|
+
return deniedAiLive("not declared in this plugin's manifest. Add `native: { picturesToAi: true }` to send camera pictures to the workspace's chosen AI.");
|
|
3148
|
+
}
|
|
3149
|
+
if (!pluginId || !holder) return deniedAiLive("no plugin identity \u2014 it fails closed without a screen to bind the session to.");
|
|
3150
|
+
if (!_provider3) return deniedAiLive("no live AI in this build \u2014 the app has not called setAiLiveProvider.");
|
|
3151
|
+
const provider = _provider3;
|
|
3152
|
+
const sc = screenOf(holder);
|
|
3153
|
+
const allowed = () => mayPicturesLeavePhone(capabilities);
|
|
3154
|
+
const releaseCamera = () => releaseDeviceStateHolds(aiLiveCameraHolder(holder));
|
|
3155
|
+
const tidy = async (why) => {
|
|
3156
|
+
unwatch(sc);
|
|
3157
|
+
try {
|
|
3158
|
+
await provider.stop(holder, why);
|
|
3159
|
+
} finally {
|
|
3160
|
+
await releaseCamera();
|
|
3161
|
+
}
|
|
3162
|
+
};
|
|
3163
|
+
const stopNowAndInTurn = (why) => {
|
|
3164
|
+
sc.stops++;
|
|
3165
|
+
const now = provider.stop(holder, why).catch(() => {
|
|
3166
|
+
});
|
|
3167
|
+
return inTurn(sc, async () => {
|
|
3168
|
+
await now;
|
|
3169
|
+
await tidy(why);
|
|
3170
|
+
});
|
|
3171
|
+
};
|
|
3172
|
+
const onConsentChange = () => {
|
|
3173
|
+
if (!allowed()) void stopNowAndInTurn(CONSENT_TAKEN_BACK);
|
|
3174
|
+
};
|
|
3175
|
+
return {
|
|
3176
|
+
start(opts) {
|
|
3177
|
+
if (sc.closed) return Promise.reject(stopped(SCREEN_CLOSED));
|
|
3178
|
+
const stopsWhenAsked = sc.stops;
|
|
3179
|
+
return inTurn(sc, async () => {
|
|
3180
|
+
if (sc.closed) throw stopped(SCREEN_CLOSED);
|
|
3181
|
+
if (sc.stops !== stopsWhenAsked) throw stopped(STOPPED_BEFORE_START);
|
|
3182
|
+
if (!allowed()) {
|
|
3183
|
+
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.');
|
|
3184
|
+
}
|
|
3185
|
+
unwatch(sc);
|
|
3186
|
+
sc.watch = onPicturesToAiConsentChange(onConsentChange);
|
|
3187
|
+
let snap;
|
|
3188
|
+
try {
|
|
3189
|
+
snap = await provider.start(opts || {}, holder, { visual: camera(), allowed });
|
|
3190
|
+
} catch (e) {
|
|
3191
|
+
unwatch(sc);
|
|
3192
|
+
await releaseCamera();
|
|
3193
|
+
if (!allowed()) throw denial2(CONSENT_TAKEN_BACK);
|
|
3194
|
+
throw e;
|
|
3195
|
+
}
|
|
3196
|
+
if (!allowed()) {
|
|
3197
|
+
await tidy(CONSENT_TAKEN_BACK);
|
|
3198
|
+
throw denial2(CONSENT_TAKEN_BACK);
|
|
3199
|
+
}
|
|
3200
|
+
return snap;
|
|
3201
|
+
});
|
|
3202
|
+
},
|
|
3203
|
+
stop: () => stopNowAndInTurn(),
|
|
3204
|
+
getSnapshot: () => provider.getSnapshot(holder),
|
|
3205
|
+
onEpisode: (cb) => provider.onEpisode(cb, holder),
|
|
3206
|
+
subscribe: (cb) => provider.subscribe(cb, holder)
|
|
3207
|
+
};
|
|
3208
|
+
}
|
|
3209
|
+
async function releaseAiLive(holder) {
|
|
3210
|
+
const sc = _screens.get(holder);
|
|
3211
|
+
if (!sc) {
|
|
3212
|
+
try {
|
|
3213
|
+
await _provider3?.stop(holder);
|
|
3214
|
+
} catch {
|
|
3215
|
+
}
|
|
3216
|
+
try {
|
|
3217
|
+
_provider3?.forget(holder);
|
|
3218
|
+
} catch {
|
|
3219
|
+
}
|
|
3220
|
+
await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
|
|
3221
|
+
return;
|
|
3222
|
+
}
|
|
3223
|
+
sc.closed = true;
|
|
3224
|
+
sc.stops++;
|
|
3225
|
+
const now = _provider3 ? _provider3.stop(holder).catch(() => {
|
|
3226
|
+
}) : Promise.resolve();
|
|
3227
|
+
await inTurn(sc, async () => {
|
|
3228
|
+
await now;
|
|
3229
|
+
unwatch(sc);
|
|
3230
|
+
try {
|
|
3231
|
+
await _provider3?.stop(holder);
|
|
3232
|
+
} catch {
|
|
3233
|
+
}
|
|
3234
|
+
try {
|
|
3235
|
+
_provider3?.forget(holder);
|
|
3236
|
+
} catch {
|
|
3237
|
+
}
|
|
3238
|
+
await releaseDeviceStateHolds(aiLiveCameraHolder(holder));
|
|
3239
|
+
});
|
|
3240
|
+
if (_screens.get(holder) === sc) _screens.delete(holder);
|
|
3241
|
+
}
|
|
3242
|
+
var NOTHING = { unsubscribe() {
|
|
3243
|
+
} };
|
|
3244
|
+
var aiLiveIndicator = {
|
|
3245
|
+
isSending: () => !!_provider3?.isSending(),
|
|
3246
|
+
subscribe: (cb) => _provider3?.subscribeSending(cb) ?? NOTHING
|
|
3247
|
+
};
|
|
3248
|
+
|
|
3051
3249
|
// src/pluginRuntime.ts
|
|
3052
3250
|
function mergeCaps(decl) {
|
|
3053
3251
|
if (!decl) return void 0;
|
|
@@ -3063,7 +3261,8 @@ function resolvePluginRuntimeProps(src, holder = src.pluginId) {
|
|
|
3063
3261
|
const native = gatePluginNative(getPluginNative(), capabilities, src.pluginId);
|
|
3064
3262
|
const deviceState = gateDeviceState(stateDomains, holder);
|
|
3065
3263
|
const voice = gateVoice(!!capabilities?.voice, src.pluginId);
|
|
3066
|
-
|
|
3264
|
+
const aiLive = gateAiLive(capabilities, src.pluginId, holder, () => gateDeviceState(["visual"], aiLiveCameraHolder(holder)).visual);
|
|
3265
|
+
return { device: native, native, deviceState, voice, aiLive };
|
|
3067
3266
|
}
|
|
3068
3267
|
|
|
3069
3268
|
// src/tools/loader.ts
|
|
@@ -3167,6 +3366,7 @@ export {
|
|
|
3167
3366
|
registerTools,
|
|
3168
3367
|
registerService,
|
|
3169
3368
|
PLATFORM_VOICE_CALLER,
|
|
3369
|
+
AI_LIVE_IDLE,
|
|
3170
3370
|
isActionable,
|
|
3171
3371
|
neverObserved,
|
|
3172
3372
|
explainCapability,
|
|
@@ -3203,6 +3403,10 @@ export {
|
|
|
3203
3403
|
gatePluginNative,
|
|
3204
3404
|
setCameraPreviewProvider,
|
|
3205
3405
|
getCameraPreviewProvider,
|
|
3406
|
+
setPicturesToAiConsentProvider,
|
|
3407
|
+
notifyPicturesToAiConsentChanged,
|
|
3408
|
+
onPicturesToAiConsentChange,
|
|
3409
|
+
mayPicturesLeavePhone,
|
|
3206
3410
|
registerNativePlugin,
|
|
3207
3411
|
unregisterNativePlugin,
|
|
3208
3412
|
nativePluginRegistry,
|
|
@@ -3221,6 +3425,11 @@ export {
|
|
|
3221
3425
|
setVoiceProvider,
|
|
3222
3426
|
implementedVoice,
|
|
3223
3427
|
gateVoice,
|
|
3428
|
+
CONSENT_TAKEN_BACK,
|
|
3429
|
+
setAiLiveProvider,
|
|
3430
|
+
gateAiLive,
|
|
3431
|
+
releaseAiLive,
|
|
3432
|
+
aiLiveIndicator,
|
|
3224
3433
|
resolvePluginGrants,
|
|
3225
3434
|
resolvePluginRuntimeProps,
|
|
3226
3435
|
useNativeBridge,
|
|
@@ -3255,4 +3464,4 @@ export {
|
|
|
3255
3464
|
ensureDeviceToolsLoaded,
|
|
3256
3465
|
resetDeviceToolLoader
|
|
3257
3466
|
};
|
|
3258
|
-
//# sourceMappingURL=chunk-
|
|
3467
|
+
//# sourceMappingURL=chunk-RNA6X65P.mjs.map
|