@ateam-ai-mobile/ui 0.1.10 → 0.1.11
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 +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +2 -0
- package/src/providers.ts +22 -0
- package/src/voice/voiceSession.ts +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ateam-ai-mobile/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Prebuilt ADAS chat experience for React Native — full-screen chat, chips, widget views. Built on @ateam-ai-mobile/core + @ateam-ai-mobile/plugin-runtime.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"build": "tsup"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@ateam-ai-mobile/core": "0.1.
|
|
13
|
-
"@ateam-ai-mobile/plugin-runtime": "0.1.
|
|
12
|
+
"@ateam-ai-mobile/core": "0.1.11",
|
|
13
|
+
"@ateam-ai-mobile/plugin-runtime": "0.1.11",
|
|
14
14
|
"zustand": "^5.0.0"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -80,10 +80,12 @@ export {
|
|
|
80
80
|
setUIActionNavigator,
|
|
81
81
|
setPluginWebViewExtraHosts,
|
|
82
82
|
setOAuthProvider,
|
|
83
|
+
setCallAudioProvider,
|
|
83
84
|
} from './providers';
|
|
84
85
|
export type {
|
|
85
86
|
ClipboardProvider,
|
|
86
87
|
UIActionRoute,
|
|
87
88
|
OAuthProvider,
|
|
88
89
|
OAuthGoogleConfig,
|
|
90
|
+
CallAudioProvider,
|
|
89
91
|
} from './providers';
|
package/src/providers.ts
CHANGED
|
@@ -48,6 +48,28 @@ export function getOAuthProvider(): OAuthProvider | null {
|
|
|
48
48
|
return _oauth;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// ── Call audio mode ────────────────────────────────────────────────────────
|
|
52
|
+
// A voice call needs the device in its CALL audio mode, or the phone's mic
|
|
53
|
+
// hears the loudspeaker and the AI interrupts itself (iOS: playAndRecord +
|
|
54
|
+
// voiceChat). Native, so the host wires it (via @ateam-ai-mobile/expo);
|
|
55
|
+
// voiceSession calls beginCall when a call starts and endCall when it ends.
|
|
56
|
+
|
|
57
|
+
export interface CallAudioProvider {
|
|
58
|
+
beginCall(): void;
|
|
59
|
+
endCall(): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let _callAudio: CallAudioProvider | null = null;
|
|
63
|
+
|
|
64
|
+
/** Register the device's call audio mode (e.g. via @ateam-ai-mobile/expo). */
|
|
65
|
+
export function setCallAudioProvider(callAudio: CallAudioProvider | null): void {
|
|
66
|
+
_callAudio = callAudio;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getCallAudioProvider(): CallAudioProvider | null {
|
|
70
|
+
return _callAudio;
|
|
71
|
+
}
|
|
72
|
+
|
|
51
73
|
// ── Clipboard ──────────────────────────────────────────────────────────────
|
|
52
74
|
|
|
53
75
|
export interface ClipboardProvider {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* cannot reach the WebView beyond that one injected call.
|
|
25
25
|
*/
|
|
26
26
|
import { getVoiceApiUrl, getToken, getTenant, getUser, refreshToken } from '@ateam-ai-mobile/core';
|
|
27
|
+
import { getCallAudioProvider } from '../providers';
|
|
27
28
|
import {
|
|
28
29
|
callDeviceTool,
|
|
29
30
|
ensureDeviceToolsLoaded,
|
|
@@ -284,6 +285,11 @@ interface InternalState {
|
|
|
284
285
|
persona?: VoicePersona;
|
|
285
286
|
}
|
|
286
287
|
|
|
288
|
+
/** A call that holds the mic/speaker: connecting or connected. */
|
|
289
|
+
function isLiveCall(state: VoiceState): boolean {
|
|
290
|
+
return state === 'connecting' || state === 'connected';
|
|
291
|
+
}
|
|
292
|
+
|
|
287
293
|
const IDLE: InternalState = {
|
|
288
294
|
callState: 'idle',
|
|
289
295
|
sessionId: null,
|
|
@@ -833,10 +839,26 @@ class VoiceSessionManager implements VoiceSessionProvider {
|
|
|
833
839
|
// ── internals ────────────────────────────────────────────────
|
|
834
840
|
|
|
835
841
|
private setState(partial: Partial<InternalState>): void {
|
|
842
|
+
const wasLive = isLiveCall(this.state.callState);
|
|
836
843
|
this.state = { ...this.state, ...partial };
|
|
844
|
+
const isLive = isLiveCall(this.state.callState);
|
|
845
|
+
// The device's CALL audio mode follows the call: on as it starts connecting
|
|
846
|
+
// (before the WebView opens the mic), off as soon as it is no longer live —
|
|
847
|
+
// whichever path ends it (stop(), the page hanging up, an error).
|
|
848
|
+
if (wasLive !== isLive) this.setCallAudio(isLive);
|
|
837
849
|
this.emit({ type: 'state' });
|
|
838
850
|
}
|
|
839
851
|
|
|
852
|
+
private setCallAudio(on: boolean): void {
|
|
853
|
+
const audio = getCallAudioProvider();
|
|
854
|
+
if (!audio) return;
|
|
855
|
+
try {
|
|
856
|
+
if (on) audio.beginCall(); else audio.endCall();
|
|
857
|
+
} catch (e: any) {
|
|
858
|
+
console.warn('[voiceSession] call audio mode failed:', e?.message || String(e));
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
840
862
|
private appendTranscript(entry: TranscriptEntry): void {
|
|
841
863
|
this.state = { ...this.state, transcript: [...this.state.transcript, entry] };
|
|
842
864
|
this.emit({ type: 'transcript' });
|