@ateam-ai-mobile/ui 0.1.8 → 0.1.10
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 +63 -47
- package/dist/index.d.ts +63 -47
- package/dist/index.js +163 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +195 -102
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/auth/HandoffScreen.tsx +3 -11
- package/src/auth/LoginScreen.tsx +68 -17
- package/src/auth/OpenJoinScreen.tsx +4 -6
- package/src/auth/handoffExchange.ts +6 -9
- package/src/auth/login.ts +5 -10
- package/src/auth/openJoin.ts +5 -8
- package/src/index.ts +1 -1
- package/src/plugin/EmbeddedPluginWebView.tsx +4 -1
- package/src/voice/voiceSession.ts +150 -64
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/AdasChatScreen.tsx
|
|
2
|
-
import { useCallback as useCallback5, useEffect as
|
|
2
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo3, useRef as useRef4, useState as useState6 } from "react";
|
|
3
3
|
import {
|
|
4
4
|
FlatList,
|
|
5
5
|
KeyboardAvoidingView,
|
|
@@ -238,13 +238,13 @@ function getPluginWebViewExtraHosts() {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
// src/plugin/WidgetHost.tsx
|
|
241
|
-
import { useEffect as
|
|
241
|
+
import { useEffect as useEffect5 } from "react";
|
|
242
242
|
import { create } from "zustand";
|
|
243
243
|
import { pluginCommandEmitter as pluginCommandEmitter2 } from "@ateam-ai-mobile/core";
|
|
244
244
|
import { useSurfaceStore } from "@ateam-ai-mobile/plugin-runtime";
|
|
245
245
|
|
|
246
246
|
// src/plugin/PluginSurface.tsx
|
|
247
|
-
import { useEffect as
|
|
247
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
248
248
|
import { View as View4, ActivityIndicator as ActivityIndicator3 } from "react-native";
|
|
249
249
|
import { ada as ada3 } from "@ateam-ai-mobile/core";
|
|
250
250
|
import {
|
|
@@ -265,7 +265,7 @@ import {
|
|
|
265
265
|
} from "@ateam-ai-mobile/plugin-runtime";
|
|
266
266
|
|
|
267
267
|
// src/plugin/EmbeddedPluginWebView.tsx
|
|
268
|
-
import { useState as useState2, useMemo, useCallback as useCallback2 } from "react";
|
|
268
|
+
import { useState as useState2, useMemo, useCallback as useCallback2, useEffect as useEffect3 } from "react";
|
|
269
269
|
import { View as View2, Text as Text2, ActivityIndicator, StyleSheet as StyleSheet2, Platform } from "react-native";
|
|
270
270
|
import { WebView } from "react-native-webview";
|
|
271
271
|
import { getConfig, getCoreApiUrl, getVoiceApiUrl, getTenant as getTenant2, getToken, ada as ada2 } from "@ateam-ai-mobile/core";
|
|
@@ -596,6 +596,9 @@ function EmbeddedPluginWebView({ pluginId, manifest, commandBufferRef }) {
|
|
|
596
596
|
const tenant = getTenant2();
|
|
597
597
|
const { webViewRef, sendInit, handleMessage } = usePluginBridge(pluginId, manifest._connectorId, commandBufferRef);
|
|
598
598
|
const url = resolvePluginUrl(manifest, tenant || void 0);
|
|
599
|
+
useEffect3(() => {
|
|
600
|
+
setError(null);
|
|
601
|
+
}, [url]);
|
|
599
602
|
const bridgeJS = buildPluginBridgeJS(token || "", tenant || "");
|
|
600
603
|
const computeAllowedHosts = useCallback2(() => {
|
|
601
604
|
const hosts = /* @__PURE__ */ new Set();
|
|
@@ -833,7 +836,7 @@ import { jsx as jsx4 } from "react/jsx-runtime";
|
|
|
833
836
|
function PluginSurface({ pluginId, surface, dismiss, props }) {
|
|
834
837
|
const [manifest, setManifest] = useState3(null);
|
|
835
838
|
const [error, setError] = useState3(null);
|
|
836
|
-
|
|
839
|
+
useEffect4(() => {
|
|
837
840
|
let cancelled = false;
|
|
838
841
|
getPlugin(pluginId).then((m) => {
|
|
839
842
|
if (!cancelled) m ? setManifest(m) : setError("Plugin not found");
|
|
@@ -892,7 +895,7 @@ function WidgetHost() {
|
|
|
892
895
|
const pluginId = useWidgetHostStore((s) => s.pluginId);
|
|
893
896
|
const props = useWidgetHostStore((s) => s.props);
|
|
894
897
|
const close = useWidgetHostStore((s) => s.close);
|
|
895
|
-
|
|
898
|
+
useEffect5(() => {
|
|
896
899
|
return pluginCommandEmitter2.on("focus-plugin", (data) => {
|
|
897
900
|
if (data?.pluginId) openWidget(String(data.pluginId), data.props);
|
|
898
901
|
});
|
|
@@ -1600,7 +1603,7 @@ var styles8 = StyleSheet8.create({
|
|
|
1600
1603
|
});
|
|
1601
1604
|
|
|
1602
1605
|
// src/chat/ChatInput.tsx
|
|
1603
|
-
import { useState as useState5, useRef as useRef3, useCallback as useCallback4, useEffect as
|
|
1606
|
+
import { useState as useState5, useRef as useRef3, useCallback as useCallback4, useEffect as useEffect6 } from "react";
|
|
1604
1607
|
import {
|
|
1605
1608
|
View as View10,
|
|
1606
1609
|
TextInput,
|
|
@@ -1616,7 +1619,7 @@ function ChatInput({ onSend, onCallStart, loading, prefill, placeholder }) {
|
|
|
1616
1619
|
const [text, setText] = useState5("");
|
|
1617
1620
|
const [height, setHeight] = useState5(40);
|
|
1618
1621
|
const inputRef = useRef3(null);
|
|
1619
|
-
|
|
1622
|
+
useEffect6(() => {
|
|
1620
1623
|
if (prefill) {
|
|
1621
1624
|
setText(prefill);
|
|
1622
1625
|
inputRef.current?.focus();
|
|
@@ -1777,10 +1780,10 @@ function AdasChatScreen({
|
|
|
1777
1780
|
const listRef = useRef4(null);
|
|
1778
1781
|
const [refreshing, setRefreshing] = useState6(false);
|
|
1779
1782
|
const [prefill, setPrefill] = useState6("");
|
|
1780
|
-
|
|
1783
|
+
useEffect7(() => {
|
|
1781
1784
|
if (!conversationLoaded) loadConversation();
|
|
1782
1785
|
}, [conversationLoaded, loadConversation]);
|
|
1783
|
-
|
|
1786
|
+
useEffect7(() => {
|
|
1784
1787
|
const unsub = pluginCommandEmitter3.on("prepare-chat-message", ({ text }) => {
|
|
1785
1788
|
if (text) setPrefill(text);
|
|
1786
1789
|
});
|
|
@@ -2004,7 +2007,7 @@ var styles12 = StyleSheet12.create({
|
|
|
2004
2007
|
});
|
|
2005
2008
|
|
|
2006
2009
|
// src/TenantPicker.tsx
|
|
2007
|
-
import { useEffect as
|
|
2010
|
+
import { useEffect as useEffect8, useState as useState8 } from "react";
|
|
2008
2011
|
import { View as View14, Text as Text10, Pressable as Pressable8, ActivityIndicator as ActivityIndicator5, StyleSheet as StyleSheet13, Platform as Platform9 } from "react-native";
|
|
2009
2012
|
import { ada as ada10, fontSize as fontSize6, borderRadius as borderRadius4, listMyTenants, switchTenant, getTenant as getTenant4 } from "@ateam-ai-mobile/core";
|
|
2010
2013
|
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
@@ -2014,7 +2017,7 @@ function TenantPicker({ onSwitched, onSelect, currentTenantId }) {
|
|
|
2014
2017
|
const [error, setError] = useState8(null);
|
|
2015
2018
|
const [switching, setSwitching] = useState8(null);
|
|
2016
2019
|
const active = currentTenantId ?? getTenant4();
|
|
2017
|
-
|
|
2020
|
+
useEffect8(() => {
|
|
2018
2021
|
let cancelled = false;
|
|
2019
2022
|
listMyTenants().then((list) => {
|
|
2020
2023
|
if (!cancelled) setTenants(list);
|
|
@@ -2185,7 +2188,7 @@ var styles14 = StyleSheet14.create({
|
|
|
2185
2188
|
});
|
|
2186
2189
|
|
|
2187
2190
|
// src/auth/HandoffScreen.tsx
|
|
2188
|
-
import { useEffect as
|
|
2191
|
+
import { useEffect as useEffect9, useRef as useRef5, useState as useState9 } from "react";
|
|
2189
2192
|
import { View as View16, Text as Text12, Pressable as Pressable9, StyleSheet as StyleSheet15, Platform as Platform10, ActivityIndicator as ActivityIndicator6 } from "react-native";
|
|
2190
2193
|
import { exchangeHandoff, ada as ada12 } from "@ateam-ai-mobile/core";
|
|
2191
2194
|
import { AdaOrb as AdaOrb3 } from "@ateam-ai-mobile/plugin-runtime";
|
|
@@ -2193,7 +2196,6 @@ import { AdaOrb as AdaOrb3 } from "@ateam-ai-mobile/plugin-runtime";
|
|
|
2193
2196
|
// src/auth/handoffExchange.ts
|
|
2194
2197
|
async function runHandoffExchange(code, deps) {
|
|
2195
2198
|
const res = await deps.exchange(code);
|
|
2196
|
-
if (res.tenant) await deps.onAdoptTenant(res.tenant);
|
|
2197
2199
|
await deps.onSignedIn(res.jwt);
|
|
2198
2200
|
deps.onDone();
|
|
2199
2201
|
}
|
|
@@ -2208,14 +2210,14 @@ function handoffErrorMessage(msg) {
|
|
|
2208
2210
|
// src/auth/HandoffScreen.tsx
|
|
2209
2211
|
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2210
2212
|
var fontFam7 = Platform10.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2211
|
-
function HandoffScreen({ code,
|
|
2213
|
+
function HandoffScreen({ code, onSignedIn, onDone, onCancel }) {
|
|
2212
2214
|
const [err, setErr] = useState9(null);
|
|
2213
2215
|
const startedForRef = useRef5(null);
|
|
2214
|
-
|
|
2216
|
+
useEffect9(() => {
|
|
2215
2217
|
if (!code || startedForRef.current === code) return;
|
|
2216
2218
|
startedForRef.current = code;
|
|
2217
|
-
runHandoffExchange(code, { exchange: exchangeHandoff,
|
|
2218
|
-
}, [code,
|
|
2219
|
+
runHandoffExchange(code, { exchange: exchangeHandoff, onSignedIn, onDone }).catch((e) => setErr(handoffErrorMessage(e?.message)));
|
|
2220
|
+
}, [code, onSignedIn, onDone]);
|
|
2219
2221
|
return /* @__PURE__ */ jsx17(View16, { style: styles15.container, children: /* @__PURE__ */ jsxs13(View16, { style: styles15.center, children: [
|
|
2220
2222
|
/* @__PURE__ */ jsx17(AdaOrb3, { size: 72, state: err ? "idle" : "thinking" }),
|
|
2221
2223
|
!err ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
|
|
@@ -2238,7 +2240,7 @@ var styles15 = StyleSheet15.create({
|
|
|
2238
2240
|
});
|
|
2239
2241
|
|
|
2240
2242
|
// src/auth/OpenJoinScreen.tsx
|
|
2241
|
-
import { useEffect as
|
|
2243
|
+
import { useEffect as useEffect10, useState as useState10 } from "react";
|
|
2242
2244
|
import { View as View17, Text as Text13, Pressable as Pressable10, StyleSheet as StyleSheet16, ActivityIndicator as ActivityIndicator7, Platform as Platform11, TextInput as TextInput2 } from "react-native";
|
|
2243
2245
|
import { openJoinWithGoogle, openJoinWithApple, ada as ada13, spacing as spacing3 } from "@ateam-ai-mobile/core";
|
|
2244
2246
|
import { AdaOrb as AdaOrb4 } from "@ateam-ai-mobile/plugin-runtime";
|
|
@@ -2247,7 +2249,6 @@ import { AdaOrb as AdaOrb4 } from "@ateam-ai-mobile/plugin-runtime";
|
|
|
2247
2249
|
async function completeOpenJoin(slug, idToken, deps) {
|
|
2248
2250
|
if (!idToken) return false;
|
|
2249
2251
|
const consumer = await deps.join(slug, idToken);
|
|
2250
|
-
await deps.onAdoptTenant(slug);
|
|
2251
2252
|
await deps.onSignedIn(consumer.jwt);
|
|
2252
2253
|
return true;
|
|
2253
2254
|
}
|
|
@@ -2265,12 +2266,12 @@ function openJoinErrorMessage(msg) {
|
|
|
2265
2266
|
// src/auth/OpenJoinScreen.tsx
|
|
2266
2267
|
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2267
2268
|
var fontFam8 = Platform11.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2268
|
-
function OpenJoinScreen({
|
|
2269
|
+
function OpenJoinScreen({ onSignedIn, onBack }) {
|
|
2269
2270
|
const [team, setTeam] = useState10("");
|
|
2270
2271
|
const [busy, setBusy] = useState10(false);
|
|
2271
2272
|
const [err, setErr] = useState10(null);
|
|
2272
2273
|
const [appleAvailable, setAppleAvailable] = useState10(false);
|
|
2273
|
-
|
|
2274
|
+
useEffect10(() => {
|
|
2274
2275
|
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2275
2276
|
}, []);
|
|
2276
2277
|
const slug = team.trim().toLowerCase();
|
|
@@ -2286,7 +2287,7 @@ function OpenJoinScreen({ onAdoptTenant, onSignedIn, onBack }) {
|
|
|
2286
2287
|
setBusy(true);
|
|
2287
2288
|
try {
|
|
2288
2289
|
const idToken = await acquire(oauth);
|
|
2289
|
-
await completeOpenJoin(slug, idToken, { join,
|
|
2290
|
+
await completeOpenJoin(slug, idToken, { join, onSignedIn });
|
|
2290
2291
|
} catch (e) {
|
|
2291
2292
|
setErr(openJoinErrorMessage(e?.message));
|
|
2292
2293
|
} finally {
|
|
@@ -2369,7 +2370,7 @@ var styles16 = StyleSheet16.create({
|
|
|
2369
2370
|
});
|
|
2370
2371
|
|
|
2371
2372
|
// src/auth/JoinScreen.tsx
|
|
2372
|
-
import { useEffect as
|
|
2373
|
+
import { useEffect as useEffect11, useMemo as useMemo5, useState as useState11 } from "react";
|
|
2373
2374
|
import { View as View18, Text as Text14, Pressable as Pressable11, StyleSheet as StyleSheet17, ActivityIndicator as ActivityIndicator8, Platform as Platform12 } from "react-native";
|
|
2374
2375
|
import {
|
|
2375
2376
|
previewInvite,
|
|
@@ -2402,13 +2403,13 @@ function JoinScreen({ code, onSignedIn, onDone, onCancel }) {
|
|
|
2402
2403
|
const [busy, setBusy] = useState11(false);
|
|
2403
2404
|
const [err, setErr] = useState11(null);
|
|
2404
2405
|
const [appleAvailable, setAppleAvailable] = useState11(false);
|
|
2405
|
-
|
|
2406
|
+
useEffect11(() => {
|
|
2406
2407
|
if (!code) return;
|
|
2407
2408
|
setPreview(null);
|
|
2408
2409
|
setLoadErr(null);
|
|
2409
2410
|
previewInvite(code).then(setPreview).catch((e) => setLoadErr(e?.message || "Could not load invite"));
|
|
2410
2411
|
}, [code]);
|
|
2411
|
-
|
|
2412
|
+
useEffect11(() => {
|
|
2412
2413
|
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2413
2414
|
}, []);
|
|
2414
2415
|
const orgLine = useMemo5(() => inviteHeadline(preview), [preview]);
|
|
@@ -2487,8 +2488,8 @@ var styles17 = StyleSheet17.create({
|
|
|
2487
2488
|
});
|
|
2488
2489
|
|
|
2489
2490
|
// src/auth/LoginScreen.tsx
|
|
2490
|
-
import { useEffect as
|
|
2491
|
-
import { View as View19, Text as Text15, Pressable as Pressable12, StyleSheet as StyleSheet18, Platform as Platform13, ActivityIndicator as ActivityIndicator9 } from "react-native";
|
|
2491
|
+
import { useEffect as useEffect12, useMemo as useMemo6, useState as useState12 } from "react";
|
|
2492
|
+
import { View as View19, Text as Text15, Pressable as Pressable12, StyleSheet as StyleSheet18, Platform as Platform13, ActivityIndicator as ActivityIndicator9, TextInput as TextInput3 } from "react-native";
|
|
2492
2493
|
import { fetchConsumerConfig, signInWithGoogle, signInWithApple, ada as ada15 } from "@ateam-ai-mobile/core";
|
|
2493
2494
|
import { AdaOrb as AdaOrb6 } from "@ateam-ai-mobile/plugin-runtime";
|
|
2494
2495
|
|
|
@@ -2500,8 +2501,8 @@ function googleClientIds(config) {
|
|
|
2500
2501
|
iosClientId: g.ios_client_id || ""
|
|
2501
2502
|
};
|
|
2502
2503
|
}
|
|
2503
|
-
function
|
|
2504
|
-
return /capability not enabled/i.test(errorMsg || "")
|
|
2504
|
+
function isConsumerDisabled(errorMsg) {
|
|
2505
|
+
return /capability not enabled/i.test(errorMsg || "");
|
|
2505
2506
|
}
|
|
2506
2507
|
async function completeProviderSignIn(idToken, deps) {
|
|
2507
2508
|
if (!idToken) return false;
|
|
@@ -2513,21 +2514,32 @@ async function completeProviderSignIn(idToken, deps) {
|
|
|
2513
2514
|
// src/auth/LoginScreen.tsx
|
|
2514
2515
|
import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2515
2516
|
var fontFam10 = Platform13.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
2516
|
-
function LoginScreen({ activeTenant,
|
|
2517
|
+
function LoginScreen({ activeTenant, onPickTenant, onConsumerDisabled, onSignedIn, onJoinTeam }) {
|
|
2517
2518
|
const [config, setConfig] = useState12(null);
|
|
2518
2519
|
const [error, setError] = useState12(null);
|
|
2519
|
-
|
|
2520
|
+
const [disabledTeam, setDisabledTeam] = useState12(null);
|
|
2521
|
+
const [askTeam, setAskTeam] = useState12(false);
|
|
2522
|
+
const askingTeam = !activeTenant || askTeam;
|
|
2523
|
+
const pick = async (tenant) => {
|
|
2524
|
+
setAskTeam(false);
|
|
2525
|
+
setDisabledTeam(null);
|
|
2526
|
+
await onPickTenant(tenant);
|
|
2527
|
+
};
|
|
2528
|
+
useEffect12(() => {
|
|
2520
2529
|
setConfig(null);
|
|
2521
2530
|
setError(null);
|
|
2531
|
+
if (!activeTenant) return;
|
|
2522
2532
|
fetchConsumerConfig().then(setConfig).catch(async (err) => {
|
|
2523
2533
|
const msg = err?.message || "Failed to load sign-in config";
|
|
2524
|
-
if (
|
|
2534
|
+
if (isConsumerDisabled(msg)) {
|
|
2535
|
+
setDisabledTeam(activeTenant);
|
|
2536
|
+
setAskTeam(true);
|
|
2525
2537
|
await onConsumerDisabled();
|
|
2526
2538
|
return;
|
|
2527
2539
|
}
|
|
2528
2540
|
setError(msg);
|
|
2529
2541
|
});
|
|
2530
|
-
}, [activeTenant,
|
|
2542
|
+
}, [activeTenant, onConsumerDisabled]);
|
|
2531
2543
|
return /* @__PURE__ */ jsxs16(View19, { style: styles18.container, children: [
|
|
2532
2544
|
/* @__PURE__ */ jsxs16(View19, { style: styles18.hero, children: [
|
|
2533
2545
|
/* @__PURE__ */ jsx20(AdaOrb6, { size: 140 }),
|
|
@@ -2535,20 +2547,51 @@ function LoginScreen({ activeTenant, defaultTenant, onConsumerDisabled, onSigned
|
|
|
2535
2547
|
/* @__PURE__ */ jsx20(Text15, { style: styles18.tagline, children: "Your private personal AI-Team" })
|
|
2536
2548
|
] }),
|
|
2537
2549
|
/* @__PURE__ */ jsxs16(View19, { style: styles18.buttonSection, children: [
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
!!
|
|
2550
|
+
askingTeam && /* @__PURE__ */ jsx20(TeamField, { notice: disabledTeam, onPick: pick }),
|
|
2551
|
+
!askingTeam && !config && !error && /* @__PURE__ */ jsx20(ActivityIndicator9, { color: ada15.ink }),
|
|
2552
|
+
!askingTeam && !!error && /* @__PURE__ */ jsx20(Text15, { style: styles18.errorText, children: error }),
|
|
2553
|
+
!askingTeam && !!config && /* @__PURE__ */ jsx20(SignInButtons, { config, onSignedIn }),
|
|
2554
|
+
!askingTeam && /* @__PURE__ */ jsx20(Pressable12, { onPress: () => setAskTeam(true), hitSlop: 8, style: { paddingVertical: 4 }, children: /* @__PURE__ */ jsx20(Text15, { style: styles18.joinLink, children: "Use a different team" }) }),
|
|
2541
2555
|
onJoinTeam && /* @__PURE__ */ jsx20(Pressable12, { onPress: onJoinTeam, hitSlop: 8, style: { paddingVertical: 8 }, children: /* @__PURE__ */ jsx20(Text15, { style: styles18.joinLink, children: "Join a team by name" }) }),
|
|
2542
2556
|
/* @__PURE__ */ jsx20(Text15, { style: styles18.disclaimer, children: "By continuing you agree to Ada's Terms and Privacy Policy." })
|
|
2543
2557
|
] })
|
|
2544
2558
|
] });
|
|
2545
2559
|
}
|
|
2560
|
+
function TeamField({ notice, onPick }) {
|
|
2561
|
+
const [team, setTeam] = useState12("");
|
|
2562
|
+
const slug = team.trim().toLowerCase();
|
|
2563
|
+
const submit = () => {
|
|
2564
|
+
if (slug) void onPick(slug);
|
|
2565
|
+
};
|
|
2566
|
+
return /* @__PURE__ */ jsxs16(Fragment5, { children: [
|
|
2567
|
+
!!notice && /* @__PURE__ */ jsxs16(Text15, { style: styles18.errorText, children: [
|
|
2568
|
+
"\u201C",
|
|
2569
|
+
notice,
|
|
2570
|
+
"\u201D doesn't have app sign-in. Try another team."
|
|
2571
|
+
] }),
|
|
2572
|
+
/* @__PURE__ */ jsx20(
|
|
2573
|
+
TextInput3,
|
|
2574
|
+
{
|
|
2575
|
+
style: styles18.teamInput,
|
|
2576
|
+
value: team,
|
|
2577
|
+
onChangeText: setTeam,
|
|
2578
|
+
placeholder: "your team (e.g. acme)",
|
|
2579
|
+
placeholderTextColor: ada15.inkMuted,
|
|
2580
|
+
autoCapitalize: "none",
|
|
2581
|
+
autoCorrect: false,
|
|
2582
|
+
returnKeyType: "go",
|
|
2583
|
+
onSubmitEditing: submit
|
|
2584
|
+
}
|
|
2585
|
+
),
|
|
2586
|
+
/* @__PURE__ */ jsx20(Pressable12, { style: [styles18.signInBtn, !slug && styles18.signInBtnDisabled], onPress: submit, disabled: !slug, children: /* @__PURE__ */ jsx20(Text15, { style: styles18.signInText, children: "Continue" }) })
|
|
2587
|
+
] });
|
|
2588
|
+
}
|
|
2546
2589
|
function SignInButtons({ config, onSignedIn }) {
|
|
2547
2590
|
const [busy, setBusy] = useState12(false);
|
|
2548
2591
|
const [error, setError] = useState12(null);
|
|
2549
2592
|
const [appleAvailable, setAppleAvailable] = useState12(false);
|
|
2550
2593
|
const { webClientId, iosClientId } = useMemo6(() => googleClientIds(config), [config]);
|
|
2551
|
-
|
|
2594
|
+
useEffect12(() => {
|
|
2552
2595
|
getOAuthProvider()?.isAppleAvailable().then(setAppleAvailable).catch(() => setAppleAvailable(false));
|
|
2553
2596
|
}, []);
|
|
2554
2597
|
const handleGoogleLogin = async () => {
|
|
@@ -2636,13 +2679,24 @@ var styles18 = StyleSheet18.create({
|
|
|
2636
2679
|
signInGlyph: { fontSize: 18, fontWeight: "700", color: ada15.paper, fontFamily: fontFam10 },
|
|
2637
2680
|
signInText: { fontSize: 16, fontWeight: "600", color: ada15.paper, letterSpacing: -0.2, fontFamily: fontFam10 },
|
|
2638
2681
|
appleBtn: { width: "100%", height: 52 },
|
|
2682
|
+
teamInput: {
|
|
2683
|
+
width: "100%",
|
|
2684
|
+
backgroundColor: ada15.paperSoft,
|
|
2685
|
+
borderWidth: 1,
|
|
2686
|
+
borderColor: ada15.border,
|
|
2687
|
+
borderRadius: 14,
|
|
2688
|
+
paddingHorizontal: 16,
|
|
2689
|
+
paddingVertical: 14,
|
|
2690
|
+
fontSize: 16,
|
|
2691
|
+
color: ada15.ink
|
|
2692
|
+
},
|
|
2639
2693
|
errorText: { fontSize: 13, color: "#c43d3d", textAlign: "center", paddingHorizontal: 16 },
|
|
2640
2694
|
disclaimer: { fontSize: 12, color: ada15.inkMuted, textAlign: "center", marginTop: 8, lineHeight: 18, fontFamily: fontFam10 },
|
|
2641
2695
|
joinLink: { fontSize: 14, fontWeight: "600", color: ada15.orangeDeep, textAlign: "center", fontFamily: fontFam10 }
|
|
2642
2696
|
});
|
|
2643
2697
|
|
|
2644
2698
|
// src/voice/VoiceCallSheet.tsx
|
|
2645
|
-
import { useEffect as
|
|
2699
|
+
import { useEffect as useEffect14, useRef as useRef6, useMemo as useMemo7 } from "react";
|
|
2646
2700
|
import {
|
|
2647
2701
|
View as View20,
|
|
2648
2702
|
Text as Text16,
|
|
@@ -2656,7 +2710,7 @@ import { ada as ada16 } from "@ateam-ai-mobile/core";
|
|
|
2656
2710
|
import { AdaOrb as AdaOrb7, SurfaceFullscreen as SurfaceFullscreen2 } from "@ateam-ai-mobile/plugin-runtime";
|
|
2657
2711
|
|
|
2658
2712
|
// src/voice/useVoiceCall.ts
|
|
2659
|
-
import { useCallback as useCallback6, useEffect as
|
|
2713
|
+
import { useCallback as useCallback6, useEffect as useEffect13, useReducer } from "react";
|
|
2660
2714
|
|
|
2661
2715
|
// src/voice/voiceSession.ts
|
|
2662
2716
|
import { getVoiceApiUrl as getVoiceApiUrl2, getToken as getToken2, getTenant as getTenant5, getUser as getUser2, refreshToken } from "@ateam-ai-mobile/core";
|
|
@@ -2800,6 +2854,11 @@ var buildObserveScript = (text) => `
|
|
|
2800
2854
|
}
|
|
2801
2855
|
})(${JSON.stringify(text)}); true;
|
|
2802
2856
|
`;
|
|
2857
|
+
var DEVICE_TOOL_ERROR_MAX = 200;
|
|
2858
|
+
function clipError(message) {
|
|
2859
|
+
const chars = Array.from(message);
|
|
2860
|
+
return chars.length > DEVICE_TOOL_ERROR_MAX ? chars.slice(0, DEVICE_TOOL_ERROR_MAX - 1).join("") + "\u2026" : message;
|
|
2861
|
+
}
|
|
2803
2862
|
function originOf(url) {
|
|
2804
2863
|
if (!url) return null;
|
|
2805
2864
|
const m = /^([a-z][a-z0-9+.-]*:\/\/[^/?#]+)/i.exec(url);
|
|
@@ -2815,7 +2874,7 @@ var IDLE = {
|
|
|
2815
2874
|
muted: false,
|
|
2816
2875
|
userSpeaking: false,
|
|
2817
2876
|
lastUserSpeechEndedAt: null,
|
|
2818
|
-
|
|
2877
|
+
deviceToolCalls: [],
|
|
2819
2878
|
mounted: false,
|
|
2820
2879
|
webViewSource: null,
|
|
2821
2880
|
skillSlug: void 0
|
|
@@ -2871,6 +2930,11 @@ var VoiceSessionManager = class {
|
|
|
2871
2930
|
* and the bundleManager registers a plugin's tools under that same id (never
|
|
2872
2931
|
* the bundle's own short `id`), so exact equality is the whole check. */
|
|
2873
2932
|
this.toolScope = null;
|
|
2933
|
+
/** Bumped whenever a session begins or ends. A device-tool call remembers the
|
|
2934
|
+
* epoch it arrived in, and its outcome is recorded only if that session is
|
|
2935
|
+
* still the current one — a tool that finishes after hang-up (or after a new
|
|
2936
|
+
* call started) must not show up as the new session's last call. */
|
|
2937
|
+
this.sessionEpoch = 0;
|
|
2874
2938
|
this.injectedTrackHook = INJECT_TRACK_HOOK;
|
|
2875
2939
|
}
|
|
2876
2940
|
/** The platform (built-in sheet, mic indicator, session host) sees and
|
|
@@ -2900,11 +2964,11 @@ var VoiceSessionManager = class {
|
|
|
2900
2964
|
async start(opts, caller = PLATFORM_VOICE_CALLER) {
|
|
2901
2965
|
if (this.state.callState === "connected") {
|
|
2902
2966
|
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2903
|
-
return this.realSnapshot();
|
|
2967
|
+
return this.realSnapshot(caller);
|
|
2904
2968
|
}
|
|
2905
2969
|
if (this.state.callState === "connecting") {
|
|
2906
2970
|
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2907
|
-
return this.waitForConnect();
|
|
2971
|
+
return this.waitForConnect(caller);
|
|
2908
2972
|
}
|
|
2909
2973
|
if (opts?.skills === "none" && opts?.skillSlug) {
|
|
2910
2974
|
throw new Error("voice: skills:'none' (a clean call) cannot also hand the mic to a skill (skillSlug).");
|
|
@@ -2925,16 +2989,17 @@ var VoiceSessionManager = class {
|
|
|
2925
2989
|
const after = this.getInternal().callState;
|
|
2926
2990
|
if (after === "connected") {
|
|
2927
2991
|
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2928
|
-
return this.realSnapshot();
|
|
2992
|
+
return this.realSnapshot(caller);
|
|
2929
2993
|
}
|
|
2930
2994
|
if (after === "connecting") {
|
|
2931
2995
|
if (!this.canAccess(caller)) throw this.foreignError();
|
|
2932
|
-
return this.waitForConnect();
|
|
2996
|
+
return this.waitForConnect(caller);
|
|
2933
2997
|
}
|
|
2934
2998
|
this.owner = caller;
|
|
2935
2999
|
this.toolScope = opts?.skills === "none" && typeof caller === "string" ? caller : null;
|
|
2936
3000
|
this.frozenTools = null;
|
|
2937
3001
|
this.frozenSessionId = null;
|
|
3002
|
+
this.sessionEpoch++;
|
|
2938
3003
|
const skillSlug = opts?.skillSlug;
|
|
2939
3004
|
this.setState({
|
|
2940
3005
|
callState: "connecting",
|
|
@@ -2943,12 +3008,15 @@ var VoiceSessionManager = class {
|
|
|
2943
3008
|
aiPartial: "",
|
|
2944
3009
|
userPartial: "",
|
|
2945
3010
|
muted: false,
|
|
3011
|
+
// A session that ended from inside the voice page (not via stop()) left
|
|
3012
|
+
// its calls here; the new session starts with none.
|
|
3013
|
+
deviceToolCalls: [],
|
|
2946
3014
|
mounted: true,
|
|
2947
3015
|
skillSlug,
|
|
2948
3016
|
persona: opts?.persona,
|
|
2949
3017
|
webViewSource: { uri: this.buildUri(skillSlug, opts?.persona, opts?.skills) }
|
|
2950
3018
|
});
|
|
2951
|
-
return this.waitForConnect();
|
|
3019
|
+
return this.waitForConnect(caller);
|
|
2952
3020
|
}
|
|
2953
3021
|
stop(caller = PLATFORM_VOICE_CALLER) {
|
|
2954
3022
|
if (this.state.callState !== "idle" && !this.canAccess(caller)) throw this.foreignError();
|
|
@@ -2962,6 +3030,7 @@ var VoiceSessionManager = class {
|
|
|
2962
3030
|
this.rejectPending(new Error("voice: session stopped before it connected"));
|
|
2963
3031
|
this.frozenTools = null;
|
|
2964
3032
|
this.frozenSessionId = null;
|
|
3033
|
+
this.sessionEpoch++;
|
|
2965
3034
|
this.setState({
|
|
2966
3035
|
...IDLE,
|
|
2967
3036
|
// keep the transcript of the call that just ended for any reader still up
|
|
@@ -2994,9 +3063,11 @@ var VoiceSessionManager = class {
|
|
|
2994
3063
|
this.webView?.injectJavaScript?.(buildObserveScript(text));
|
|
2995
3064
|
}
|
|
2996
3065
|
getSnapshot(caller = PLATFORM_VOICE_CALLER) {
|
|
2997
|
-
return this.canAccess(caller) ? this.realSnapshot() : this.foreignSnapshot();
|
|
3066
|
+
return this.canAccess(caller) ? this.realSnapshot(caller) : this.foreignSnapshot();
|
|
2998
3067
|
}
|
|
2999
|
-
|
|
3068
|
+
/** The snapshot for a caller that may access the session. Everything is the
|
|
3069
|
+
* session's, except `lastDeviceTool`, which is scoped to the caller's tools. */
|
|
3070
|
+
realSnapshot(caller) {
|
|
3000
3071
|
const s = this.state;
|
|
3001
3072
|
return {
|
|
3002
3073
|
state: s.callState,
|
|
@@ -3006,11 +3077,23 @@ var VoiceSessionManager = class {
|
|
|
3006
3077
|
listening: !!s.userPartial,
|
|
3007
3078
|
userSpeaking: s.userSpeaking,
|
|
3008
3079
|
lastUserSpeechEndedAt: s.lastUserSpeechEndedAt,
|
|
3009
|
-
lastDeviceTool:
|
|
3080
|
+
lastDeviceTool: this.lastDeviceToolFor(caller),
|
|
3010
3081
|
authorizedSessionId: this.frozenSessionId,
|
|
3011
3082
|
lastError: s.error
|
|
3012
3083
|
};
|
|
3013
3084
|
}
|
|
3085
|
+
/**
|
|
3086
|
+
* The last finished device-tool call THIS caller may see. The platform (the
|
|
3087
|
+
* user's own surface) sees every call. A plugin sees only calls to tools it
|
|
3088
|
+
* registered — even on a session it owns, the model can call another
|
|
3089
|
+
* solution's tool (a normal call offers every registered tool), and that
|
|
3090
|
+
* tool's name and error are not this plugin's to read.
|
|
3091
|
+
*/
|
|
3092
|
+
lastDeviceToolFor(caller) {
|
|
3093
|
+
const calls = this.state.deviceToolCalls;
|
|
3094
|
+
if (caller === PLATFORM_VOICE_CALLER) return calls.length ? calls[calls.length - 1].call : null;
|
|
3095
|
+
return calls.find((r) => r.owner === caller)?.call ?? null;
|
|
3096
|
+
}
|
|
3014
3097
|
foreignSnapshot() {
|
|
3015
3098
|
return {
|
|
3016
3099
|
state: "idle",
|
|
@@ -3138,18 +3221,52 @@ var VoiceSessionManager = class {
|
|
|
3138
3221
|
console.warn(`[voiceSession] REFUSED device tool call from "${sender || "unknown origin"}" (expected "${expected}")`);
|
|
3139
3222
|
break;
|
|
3140
3223
|
}
|
|
3141
|
-
|
|
3142
|
-
if (!this.isToolAuthorized(data.name)) {
|
|
3143
|
-
const notReady = this.frozenTools === null;
|
|
3144
|
-
console.warn(`[voiceSession] REFUSED "${data.name}" \u2014 ${notReady ? "allowset not received yet" : "not authorized for this session"}`);
|
|
3145
|
-
this.postDeviceToolRefusal(data.correlationId, data.name, notReady);
|
|
3146
|
-
break;
|
|
3147
|
-
}
|
|
3148
|
-
void this.runDeviceTool(data);
|
|
3224
|
+
void this.handleDeviceToolCall(data);
|
|
3149
3225
|
break;
|
|
3150
3226
|
}
|
|
3151
3227
|
}
|
|
3152
3228
|
}
|
|
3229
|
+
/**
|
|
3230
|
+
* One device-tool call, arrival to outcome: validate → authorize → run. The
|
|
3231
|
+
* answer goes back to the mini-app (the model reads it) AND becomes
|
|
3232
|
+
* `lastDeviceTool` — the same object, recorded only once it is known, so a
|
|
3233
|
+
* refused call never looks like one that ran.
|
|
3234
|
+
*/
|
|
3235
|
+
async handleDeviceToolCall(data) {
|
|
3236
|
+
const { correlationId, name, args, timeoutMs } = data || {};
|
|
3237
|
+
const at = Date.now();
|
|
3238
|
+
const epoch = this.sessionEpoch;
|
|
3239
|
+
const toolName = typeof name === "string" ? name : "";
|
|
3240
|
+
const sessionOwner = this.owner;
|
|
3241
|
+
const owner = typeof sessionOwner === "string" && toolName && hasDeviceTool(toolName, sessionOwner) ? sessionOwner : null;
|
|
3242
|
+
let answer;
|
|
3243
|
+
if (!toolName) {
|
|
3244
|
+
answer = { ok: false, reason: "invalid", error: "The device tool call named no tool." };
|
|
3245
|
+
} else if (!correlationId) {
|
|
3246
|
+
answer = {
|
|
3247
|
+
ok: false,
|
|
3248
|
+
reason: "invalid",
|
|
3249
|
+
error: `The call to "${toolName}" carried no correlationId, so it could not be answered.`
|
|
3250
|
+
};
|
|
3251
|
+
} else if (!this.isToolAuthorized(toolName)) {
|
|
3252
|
+
const notReady = this.frozenTools === null;
|
|
3253
|
+
console.warn(`[voiceSession] REFUSED "${toolName}" \u2014 ${notReady ? "allowset not received yet" : "not authorized for this session"}`);
|
|
3254
|
+
answer = notReady ? {
|
|
3255
|
+
ok: false,
|
|
3256
|
+
reason: "not_ready",
|
|
3257
|
+
error: "The voice session is still starting up \u2014 its tool allowset has not arrived yet. Try again in a moment."
|
|
3258
|
+
} : { ok: false, reason: "not_authorized", error: `"${toolName}" is not available in this voice session.` };
|
|
3259
|
+
} else {
|
|
3260
|
+
answer = await this.runDeviceTool(toolName, args, timeoutMs);
|
|
3261
|
+
}
|
|
3262
|
+
if (correlationId) this.postDeviceToolResult({ correlationId, ...answer });
|
|
3263
|
+
if (epoch !== this.sessionEpoch) return;
|
|
3264
|
+
const ms = Math.max(0, Date.now() - at);
|
|
3265
|
+
const call = answer.ok ? { name: toolName, at, ms, ok: true, reason: null, error: null } : { name: toolName, at, ms, ok: false, reason: answer.reason, error: clipError(answer.error) };
|
|
3266
|
+
this.setState({
|
|
3267
|
+
deviceToolCalls: [...this.state.deviceToolCalls.filter((r) => r.owner !== owner), { owner, call }]
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3153
3270
|
/**
|
|
3154
3271
|
* Final authorization = Core's frozen allowset ∩ the current valid local
|
|
3155
3272
|
* registry, bound to the ACTIVE session. All must hold:
|
|
@@ -3169,21 +3286,9 @@ var VoiceSessionManager = class {
|
|
|
3169
3286
|
if (!this.frozenTools.has(name)) return false;
|
|
3170
3287
|
return hasDeviceTool(name, this.toolScope ?? void 0);
|
|
3171
3288
|
}
|
|
3172
|
-
/**
|
|
3173
|
-
*
|
|
3174
|
-
|
|
3175
|
-
postDeviceToolRefusal(correlationId, name, notReady) {
|
|
3176
|
-
const payload = notReady ? {
|
|
3177
|
-
correlationId,
|
|
3178
|
-
ok: false,
|
|
3179
|
-
reason: "not_ready",
|
|
3180
|
-
error: "The voice session is still starting up \u2014 its tool allowset has not arrived yet. Try again in a moment."
|
|
3181
|
-
} : {
|
|
3182
|
-
correlationId,
|
|
3183
|
-
ok: false,
|
|
3184
|
-
reason: "not_authorized",
|
|
3185
|
-
error: `"${name}" is not available in this voice session.`
|
|
3186
|
-
};
|
|
3289
|
+
/** Answer the mini-app's pending device-tool request (a call's outcome, or the
|
|
3290
|
+
* tool list) — it resolves the request with this payload by correlationId. */
|
|
3291
|
+
postDeviceToolResult(payload) {
|
|
3187
3292
|
this.webView?.injectJavaScript?.(
|
|
3188
3293
|
`window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
|
|
3189
3294
|
JSON.stringify(payload)
|
|
@@ -3200,28 +3305,16 @@ var VoiceSessionManager = class {
|
|
|
3200
3305
|
description: t.description,
|
|
3201
3306
|
input_schema: t.input_schema
|
|
3202
3307
|
}));
|
|
3203
|
-
this.
|
|
3204
|
-
`window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
|
|
3205
|
-
JSON.stringify({ correlationId, ok: true, tools })
|
|
3206
|
-
)}); true;`
|
|
3207
|
-
);
|
|
3308
|
+
this.postDeviceToolResult({ correlationId, ok: true, tools });
|
|
3208
3309
|
}
|
|
3209
|
-
/** Run
|
|
3210
|
-
async runDeviceTool(
|
|
3211
|
-
const { correlationId, name, args, timeoutMs } = data || {};
|
|
3212
|
-
if (!correlationId || typeof name !== "string") return;
|
|
3213
|
-
let payload;
|
|
3310
|
+
/** Run an authorized device tool. Never throws: every failure is an answer. */
|
|
3311
|
+
async runDeviceTool(name, args, timeoutMs) {
|
|
3214
3312
|
try {
|
|
3215
3313
|
const outcome = await callDeviceTool(name, args || {}, { timeoutMs });
|
|
3216
|
-
|
|
3314
|
+
return outcome.ok ? { ok: true, result: outcome.result } : { ok: false, reason: outcome.reason, error: outcome.error };
|
|
3217
3315
|
} catch (err) {
|
|
3218
|
-
|
|
3316
|
+
return { ok: false, reason: "failed", error: err?.message || String(err) };
|
|
3219
3317
|
}
|
|
3220
|
-
this.webView?.injectJavaScript?.(
|
|
3221
|
-
`window.__adasDeviceToolResult && window.__adasDeviceToolResult(${JSON.stringify(
|
|
3222
|
-
JSON.stringify(payload)
|
|
3223
|
-
)}); true;`
|
|
3224
|
-
);
|
|
3225
3318
|
}
|
|
3226
3319
|
// ── internals ────────────────────────────────────────────────
|
|
3227
3320
|
setState(partial) {
|
|
@@ -3241,22 +3334,21 @@ var VoiceSessionManager = class {
|
|
|
3241
3334
|
}
|
|
3242
3335
|
}
|
|
3243
3336
|
}
|
|
3244
|
-
waitForConnect() {
|
|
3337
|
+
waitForConnect(caller) {
|
|
3245
3338
|
return new Promise((resolve, reject) => {
|
|
3246
3339
|
const timer = setTimeout(() => {
|
|
3247
3340
|
this.pending = this.pending.filter((p) => p.timer !== timer);
|
|
3248
3341
|
reject(new Error("voice: timed out waiting to connect (is VoiceSessionHost mounted?)"));
|
|
3249
3342
|
}, CONNECT_TIMEOUT_MS);
|
|
3250
|
-
this.pending.push({ resolve, reject, timer });
|
|
3343
|
+
this.pending.push({ caller, resolve, reject, timer });
|
|
3251
3344
|
});
|
|
3252
3345
|
}
|
|
3253
3346
|
resolvePending() {
|
|
3254
|
-
const snap = this.realSnapshot();
|
|
3255
3347
|
const waiting = this.pending;
|
|
3256
3348
|
this.pending = [];
|
|
3257
3349
|
for (const p of waiting) {
|
|
3258
3350
|
clearTimeout(p.timer);
|
|
3259
|
-
p.resolve(
|
|
3351
|
+
p.resolve(this.realSnapshot(p.caller));
|
|
3260
3352
|
}
|
|
3261
3353
|
}
|
|
3262
3354
|
rejectPending(err) {
|
|
@@ -3277,6 +3369,7 @@ var VoiceSessionManager = class {
|
|
|
3277
3369
|
this.pendingStarts.clear();
|
|
3278
3370
|
this.frozenTools = null;
|
|
3279
3371
|
this.frozenSessionId = null;
|
|
3372
|
+
this.sessionEpoch++;
|
|
3280
3373
|
this.listeners.clear();
|
|
3281
3374
|
this.webView = null;
|
|
3282
3375
|
}
|
|
@@ -3286,7 +3379,7 @@ var voiceSession = new VoiceSessionManager();
|
|
|
3286
3379
|
// src/voice/useVoiceCall.ts
|
|
3287
3380
|
function useVoiceCall({ skillSlug } = {}) {
|
|
3288
3381
|
const [, force] = useReducer((x) => x + 1, 0);
|
|
3289
|
-
|
|
3382
|
+
useEffect13(() => {
|
|
3290
3383
|
const sub = voiceSession.subscribe(() => force());
|
|
3291
3384
|
return () => sub.unsubscribe();
|
|
3292
3385
|
}, []);
|
|
@@ -3375,10 +3468,10 @@ function VoiceCallSheet({ visible, onClose, skillSlug }) {
|
|
|
3375
3468
|
toggleMute
|
|
3376
3469
|
} = useVoiceCall({ skillSlug });
|
|
3377
3470
|
const scrollRef = useRef6(null);
|
|
3378
|
-
|
|
3471
|
+
useEffect14(() => {
|
|
3379
3472
|
if (visible && callState === "idle") startCall();
|
|
3380
3473
|
}, [visible]);
|
|
3381
|
-
|
|
3474
|
+
useEffect14(() => {
|
|
3382
3475
|
scrollRef.current?.scrollToEnd?.({ animated: true });
|
|
3383
3476
|
}, [transcript.length, aiPartial, userPartial]);
|
|
3384
3477
|
const handleHangUp = () => {
|
|
@@ -3571,14 +3664,14 @@ var styles19 = StyleSheet19.create({
|
|
|
3571
3664
|
});
|
|
3572
3665
|
|
|
3573
3666
|
// src/voice/VoiceSessionHost.tsx
|
|
3574
|
-
import { useCallback as useCallback7, useEffect as
|
|
3667
|
+
import { useCallback as useCallback7, useEffect as useEffect15, useReducer as useReducer2, useRef as useRef7 } from "react";
|
|
3575
3668
|
import { View as View21, StyleSheet as StyleSheet20 } from "react-native";
|
|
3576
3669
|
import { WebView as WebView3 } from "react-native-webview";
|
|
3577
3670
|
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
3578
3671
|
function VoiceSessionHost() {
|
|
3579
3672
|
const [, force] = useReducer2((x) => x + 1, 0);
|
|
3580
3673
|
const lastSig = useRef7("");
|
|
3581
|
-
|
|
3674
|
+
useEffect15(() => {
|
|
3582
3675
|
const sub = voiceSession.subscribe(() => {
|
|
3583
3676
|
const s2 = voiceSession.getInternal();
|
|
3584
3677
|
const sig = `${s2.mounted}|${s2.webViewSource?.uri || ""}`;
|
|
@@ -3624,7 +3717,7 @@ var styles20 = StyleSheet20.create({
|
|
|
3624
3717
|
});
|
|
3625
3718
|
|
|
3626
3719
|
// src/voice/VoiceMicIndicator.tsx
|
|
3627
|
-
import { useEffect as
|
|
3720
|
+
import { useEffect as useEffect16, useReducer as useReducer3, useRef as useRef8 } from "react";
|
|
3628
3721
|
import { View as View22, Text as Text17, Animated as Animated2, StyleSheet as StyleSheet21, Platform as Platform15 } from "react-native";
|
|
3629
3722
|
import { ada as ada17 } from "@ateam-ai-mobile/core";
|
|
3630
3723
|
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
@@ -3632,13 +3725,13 @@ var fontFam12 = Platform15.OS === "ios" ? "SF Pro Rounded" : void 0;
|
|
|
3632
3725
|
function VoiceMicIndicator({ topInset = 8 }) {
|
|
3633
3726
|
const [, force] = useReducer3((x) => x + 1, 0);
|
|
3634
3727
|
const pulse = useRef8(new Animated2.Value(0.4)).current;
|
|
3635
|
-
|
|
3728
|
+
useEffect16(() => {
|
|
3636
3729
|
const sub = voiceSession.subscribe(() => force());
|
|
3637
3730
|
return () => sub.unsubscribe();
|
|
3638
3731
|
}, []);
|
|
3639
3732
|
const snap = voiceSession.getSnapshot();
|
|
3640
3733
|
const live = snap.state === "connecting" || snap.state === "connected";
|
|
3641
|
-
|
|
3734
|
+
useEffect16(() => {
|
|
3642
3735
|
if (!live) return;
|
|
3643
3736
|
const loop = Animated2.loop(
|
|
3644
3737
|
Animated2.sequence([
|
|
@@ -3723,6 +3816,7 @@ export {
|
|
|
3723
3816
|
googleClientIds,
|
|
3724
3817
|
handoffErrorMessage,
|
|
3725
3818
|
inviteHeadline,
|
|
3819
|
+
isConsumerDisabled,
|
|
3726
3820
|
openJoinErrorMessage,
|
|
3727
3821
|
openWidget,
|
|
3728
3822
|
runHandoffExchange,
|
|
@@ -3730,7 +3824,6 @@ export {
|
|
|
3730
3824
|
setOAuthProvider,
|
|
3731
3825
|
setPluginWebViewExtraHosts,
|
|
3732
3826
|
setUIActionNavigator,
|
|
3733
|
-
shouldRecoverToDefaultTenant,
|
|
3734
3827
|
useLightboxStore,
|
|
3735
3828
|
usePluginBridge,
|
|
3736
3829
|
useVoiceCall,
|