@alia.onl/sdk 13.2.0 → 15.2.1
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/CHANGELOG.md +129 -0
- package/README.md +52 -20
- package/package.json +8 -4
- package/src/components/AliaAvatarIcon.tsx +30 -0
- package/src/components/AliaChatContent.tsx +4 -7
- package/src/components/AliaChatMessageList.tsx +2 -10
- package/src/components/AliaChatScreen.tsx +1 -1
- package/src/components/AliaChatSheet.tsx +15 -4
- package/src/components/AliaComposer.tsx +57 -11
- package/src/components/voice/VoiceControls.tsx +28 -4
- package/src/components/voice/VoiceSession.tsx +23 -7
- package/src/hooks/useAliaActivity.ts +31 -0
- package/src/hooks/useAliaChat.ts +14 -3
- package/src/hooks/useAmbientWave.ts +3 -3
- package/src/hooks/useAudioLevelMonitor.ts +2 -2
- package/src/hooks/useDictation.ts +295 -0
- package/src/hooks/useTTS.ts +24 -63
- package/src/hooks/useVoiceRoom.ts +148 -736
- package/src/index.ts +9 -3
- package/src/lib/activity-socket.ts +102 -0
- package/src/lib/activity-store.ts +53 -0
- package/src/lib/api-url.ts +2 -0
- package/src/lib/audio-level.ts +2 -2
- package/src/lib/dictation-recorder-types.ts +37 -0
- package/src/lib/dictation-recorder.native.ts +90 -0
- package/src/lib/dictation-recorder.ts +131 -0
- package/src/lib/dictation.ts +208 -0
- package/src/lib/labels.tsx +3 -0
- package/src/lib/pcm.ts +57 -0
- package/src/lib/speech-language.ts +1 -1
- package/src/lib/speech-messages.ts +43 -97
- package/src/lib/speech-synthesis.ts +5 -1
- package/src/lib/turn-state.ts +15 -0
- package/src/lib/voice-audio-engine-types.ts +59 -0
- package/src/lib/voice-audio-engine.native.ts +232 -0
- package/src/lib/voice-audio-engine.ts +350 -0
- package/src/lib/voice-call.ts +539 -0
- package/src/lib/voice-levels.ts +7 -3
- package/src/lib/voice-protocol.ts +309 -0
- package/src/types.ts +49 -4
- package/src/voice.ts +31 -12
- package/tsconfig.json +2 -0
- package/src/hooks/useSpeechToText.ts +0 -268
- package/src/lib/speech-recognition-types.ts +0 -108
- package/src/lib/speech-recognition.native.ts +0 -237
- package/src/lib/speech-recognition.ts +0 -308
- package/src/lib/voice-text.ts +0 -198
- package/src/lib/voice-turn.ts +0 -89
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client half of Alia's voice-call protocol, `GET /v1/voice/session`
|
|
3
|
+
* (ADR 0017 §3–§4).
|
|
4
|
+
*
|
|
5
|
+
* The server's copy is `packages/api/src/lib/voice/protocol.ts`; the SDK does
|
|
6
|
+
* not depend on the API package, so the shapes are restated here and
|
|
7
|
+
* `VOICE_PROTOCOL_VERSION` is what turns a mismatch into a refusal instead of a
|
|
8
|
+
* misunderstanding.
|
|
9
|
+
*
|
|
10
|
+
* - Binary, client → Alia: microphone PCM16 LE, 24 kHz, mono, ~40 ms a frame.
|
|
11
|
+
* - Binary, Alia → client: `[u8 n][n bytes: assistant item id, UTF-8][PCM16 LE]`.
|
|
12
|
+
* - Text: one JSON event per frame. Every server event after
|
|
13
|
+
* `session.accepted` carries `seq`; a resume replays from `afterSeq`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const VOICE_PROTOCOL_VERSION = 1;
|
|
17
|
+
|
|
18
|
+
export const VOICE_SESSION_PATH = '/v1/voice/session';
|
|
19
|
+
|
|
20
|
+
/** PCM16 mono at this rate, both directions. */
|
|
21
|
+
export const VOICE_SAMPLE_RATE = 24_000;
|
|
22
|
+
|
|
23
|
+
/** Samples in one ~40 ms microphone frame. */
|
|
24
|
+
export const VOICE_FRAME_SAMPLES = 960;
|
|
25
|
+
|
|
26
|
+
/** Milliseconds of audio in `bytes` of PCM16 mono at {@link VOICE_SAMPLE_RATE}. */
|
|
27
|
+
export function pcmBytesToMs(bytes: number): number {
|
|
28
|
+
return (bytes / 2 / VOICE_SAMPLE_RATE) * 1000;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ProductVoice = 'male' | 'female';
|
|
32
|
+
|
|
33
|
+
/** Codes Alia ends a call with. */
|
|
34
|
+
export type VoiceServerErrorCode =
|
|
35
|
+
| 'not-authenticated'
|
|
36
|
+
| 'credential-not-supported'
|
|
37
|
+
| 'plan-required'
|
|
38
|
+
| 'credits-exhausted'
|
|
39
|
+
| 'agent-unavailable'
|
|
40
|
+
| 'invalid-request'
|
|
41
|
+
| 'resume-unavailable'
|
|
42
|
+
| 'realtime-unavailable'
|
|
43
|
+
| 'realtime-limited'
|
|
44
|
+
| 'realtime-rejected'
|
|
45
|
+
| 'realtime-failed';
|
|
46
|
+
|
|
47
|
+
const SERVER_ERROR_CODES: ReadonlySet<string> = new Set<VoiceServerErrorCode>([
|
|
48
|
+
'not-authenticated',
|
|
49
|
+
'credential-not-supported',
|
|
50
|
+
'plan-required',
|
|
51
|
+
'credits-exhausted',
|
|
52
|
+
'agent-unavailable',
|
|
53
|
+
'invalid-request',
|
|
54
|
+
'resume-unavailable',
|
|
55
|
+
'realtime-unavailable',
|
|
56
|
+
'realtime-limited',
|
|
57
|
+
'realtime-rejected',
|
|
58
|
+
'realtime-failed',
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
/** Why a call ended. `call-moved-elsewhere` is a reason, never an error. */
|
|
62
|
+
export type VoiceCloseReason =
|
|
63
|
+
| 'hangup'
|
|
64
|
+
| 'call-moved-elsewhere'
|
|
65
|
+
| 'max-duration'
|
|
66
|
+
| 'idle-timeout'
|
|
67
|
+
| 'credits-exhausted'
|
|
68
|
+
| 'error'
|
|
69
|
+
| 'server-shutdown';
|
|
70
|
+
|
|
71
|
+
const CLOSE_REASONS: ReadonlySet<string> = new Set<VoiceCloseReason>([
|
|
72
|
+
'hangup',
|
|
73
|
+
'call-moved-elsewhere',
|
|
74
|
+
'max-duration',
|
|
75
|
+
'idle-timeout',
|
|
76
|
+
'credits-exhausted',
|
|
77
|
+
'error',
|
|
78
|
+
'server-shutdown',
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
export type VoiceRole = 'user' | 'assistant';
|
|
82
|
+
|
|
83
|
+
export type VoiceClientEvent =
|
|
84
|
+
| { type: 'auth'; token: string }
|
|
85
|
+
| {
|
|
86
|
+
type: 'session.start';
|
|
87
|
+
protocol: number;
|
|
88
|
+
conversationId: string;
|
|
89
|
+
agentId?: string;
|
|
90
|
+
voice: ProductVoice;
|
|
91
|
+
locale: string;
|
|
92
|
+
}
|
|
93
|
+
| { type: 'session.resume'; protocol: number; voiceSessionId: string; afterSeq: number }
|
|
94
|
+
| { type: 'playback.interrupted'; itemId: string; playedMs: number }
|
|
95
|
+
| { type: 'session.end' };
|
|
96
|
+
|
|
97
|
+
export type VoiceServerEvent =
|
|
98
|
+
| { type: 'auth.ok' }
|
|
99
|
+
| { type: 'session.accepted'; voiceSessionId: string; callId: string }
|
|
100
|
+
| {
|
|
101
|
+
type: 'session.ready';
|
|
102
|
+
model: { id: string; displayName: string; publisher: string };
|
|
103
|
+
maxDurationMs: number;
|
|
104
|
+
idleTimeoutMs: number;
|
|
105
|
+
resumeWindowMs: number;
|
|
106
|
+
}
|
|
107
|
+
| { type: 'input.ready' }
|
|
108
|
+
| { type: 'user.speech_started'; itemId: string }
|
|
109
|
+
| { type: 'user.speech_stopped'; itemId: string }
|
|
110
|
+
| { type: 'transcript.delta'; role: VoiceRole; itemId: string; text: string }
|
|
111
|
+
| { type: 'transcript.done'; role: VoiceRole; itemId: string; text: string }
|
|
112
|
+
| { type: 'assistant.audio_done'; itemId: string }
|
|
113
|
+
| {
|
|
114
|
+
type: 'assistant.done';
|
|
115
|
+
itemId: string | null;
|
|
116
|
+
status: 'completed' | 'cancelled' | 'incomplete' | 'failed';
|
|
117
|
+
}
|
|
118
|
+
| { type: 'tool.started'; callId: string; name: string }
|
|
119
|
+
| { type: 'tool.finished'; callId: string; name: string; ok: boolean }
|
|
120
|
+
| { type: 'approval.requested'; toolName: string }
|
|
121
|
+
| { type: 'messages.saved'; conversationId: string; messageIds: string[] }
|
|
122
|
+
| { type: 'session.warning'; code: 'ending-soon'; remainingMs: number }
|
|
123
|
+
| { type: 'session.reconnecting' }
|
|
124
|
+
| { type: 'session.resumed'; afterSeq: number }
|
|
125
|
+
| {
|
|
126
|
+
type: 'error';
|
|
127
|
+
code: VoiceServerErrorCode;
|
|
128
|
+
message: string;
|
|
129
|
+
retryable: boolean;
|
|
130
|
+
reference: string;
|
|
131
|
+
}
|
|
132
|
+
| { type: 'session.closed'; reason: VoiceCloseReason };
|
|
133
|
+
|
|
134
|
+
/** A server event as received: numbered once a session exists. */
|
|
135
|
+
export type ReceivedVoiceEvent = VoiceServerEvent & { seq?: number };
|
|
136
|
+
|
|
137
|
+
const isString = (value: unknown): value is string => typeof value === 'string';
|
|
138
|
+
const isNumber = (value: unknown): value is number =>
|
|
139
|
+
typeof value === 'number' && Number.isFinite(value);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A server event, or `null` for a frame this SDK does not understand — which
|
|
143
|
+
* it ignores rather than guesses at.
|
|
144
|
+
*/
|
|
145
|
+
export function parseVoiceServerEvent(raw: string): ReceivedVoiceEvent | null {
|
|
146
|
+
let value: unknown;
|
|
147
|
+
try {
|
|
148
|
+
value = JSON.parse(raw);
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
if (value === null || typeof value !== 'object') return null;
|
|
153
|
+
const event = value as Record<string, unknown>;
|
|
154
|
+
const seq = isNumber(event.seq) ? { seq: event.seq } : {};
|
|
155
|
+
switch (event.type) {
|
|
156
|
+
case 'auth.ok':
|
|
157
|
+
case 'input.ready':
|
|
158
|
+
case 'session.reconnecting':
|
|
159
|
+
return { type: event.type, ...seq };
|
|
160
|
+
case 'session.accepted':
|
|
161
|
+
return isString(event.voiceSessionId) && isString(event.callId)
|
|
162
|
+
? {
|
|
163
|
+
type: 'session.accepted',
|
|
164
|
+
voiceSessionId: event.voiceSessionId,
|
|
165
|
+
callId: event.callId,
|
|
166
|
+
...seq,
|
|
167
|
+
}
|
|
168
|
+
: null;
|
|
169
|
+
case 'session.ready': {
|
|
170
|
+
const model = event.model as Record<string, unknown> | undefined;
|
|
171
|
+
if (
|
|
172
|
+
!model ||
|
|
173
|
+
!isString(model.id) ||
|
|
174
|
+
!isNumber(event.maxDurationMs) ||
|
|
175
|
+
!isNumber(event.idleTimeoutMs) ||
|
|
176
|
+
!isNumber(event.resumeWindowMs)
|
|
177
|
+
)
|
|
178
|
+
return null;
|
|
179
|
+
return {
|
|
180
|
+
type: 'session.ready',
|
|
181
|
+
model: {
|
|
182
|
+
id: model.id,
|
|
183
|
+
displayName: isString(model.displayName) ? model.displayName : model.id,
|
|
184
|
+
publisher: isString(model.publisher) ? model.publisher : '',
|
|
185
|
+
},
|
|
186
|
+
maxDurationMs: event.maxDurationMs,
|
|
187
|
+
idleTimeoutMs: event.idleTimeoutMs,
|
|
188
|
+
resumeWindowMs: event.resumeWindowMs,
|
|
189
|
+
...seq,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
case 'user.speech_started':
|
|
193
|
+
case 'user.speech_stopped':
|
|
194
|
+
case 'assistant.audio_done':
|
|
195
|
+
return isString(event.itemId) ? { type: event.type, itemId: event.itemId, ...seq } : null;
|
|
196
|
+
case 'transcript.delta':
|
|
197
|
+
case 'transcript.done':
|
|
198
|
+
return (event.role === 'user' || event.role === 'assistant') &&
|
|
199
|
+
isString(event.itemId) &&
|
|
200
|
+
isString(event.text)
|
|
201
|
+
? { type: event.type, role: event.role, itemId: event.itemId, text: event.text, ...seq }
|
|
202
|
+
: null;
|
|
203
|
+
case 'assistant.done':
|
|
204
|
+
return event.itemId === null || isString(event.itemId)
|
|
205
|
+
? {
|
|
206
|
+
type: 'assistant.done',
|
|
207
|
+
itemId: event.itemId as string | null,
|
|
208
|
+
status:
|
|
209
|
+
event.status === 'cancelled' ||
|
|
210
|
+
event.status === 'incomplete' ||
|
|
211
|
+
event.status === 'failed'
|
|
212
|
+
? event.status
|
|
213
|
+
: 'completed',
|
|
214
|
+
...seq,
|
|
215
|
+
}
|
|
216
|
+
: null;
|
|
217
|
+
case 'tool.started':
|
|
218
|
+
return isString(event.callId) && isString(event.name)
|
|
219
|
+
? { type: 'tool.started', callId: event.callId, name: event.name, ...seq }
|
|
220
|
+
: null;
|
|
221
|
+
case 'tool.finished':
|
|
222
|
+
return isString(event.callId) && isString(event.name)
|
|
223
|
+
? {
|
|
224
|
+
type: 'tool.finished',
|
|
225
|
+
callId: event.callId,
|
|
226
|
+
name: event.name,
|
|
227
|
+
ok: event.ok === true,
|
|
228
|
+
...seq,
|
|
229
|
+
}
|
|
230
|
+
: null;
|
|
231
|
+
case 'approval.requested':
|
|
232
|
+
return isString(event.toolName)
|
|
233
|
+
? { type: 'approval.requested', toolName: event.toolName, ...seq }
|
|
234
|
+
: null;
|
|
235
|
+
case 'messages.saved':
|
|
236
|
+
return isString(event.conversationId) && Array.isArray(event.messageIds)
|
|
237
|
+
? {
|
|
238
|
+
type: 'messages.saved',
|
|
239
|
+
conversationId: event.conversationId,
|
|
240
|
+
messageIds: event.messageIds.filter(isString),
|
|
241
|
+
...seq,
|
|
242
|
+
}
|
|
243
|
+
: null;
|
|
244
|
+
case 'session.warning':
|
|
245
|
+
return event.code === 'ending-soon' && isNumber(event.remainingMs)
|
|
246
|
+
? { type: 'session.warning', code: 'ending-soon', remainingMs: event.remainingMs, ...seq }
|
|
247
|
+
: null;
|
|
248
|
+
case 'session.resumed':
|
|
249
|
+
return isNumber(event.afterSeq)
|
|
250
|
+
? { type: 'session.resumed', afterSeq: event.afterSeq, ...seq }
|
|
251
|
+
: null;
|
|
252
|
+
case 'error':
|
|
253
|
+
return {
|
|
254
|
+
type: 'error',
|
|
255
|
+
// A code this SDK does not know is still a failure of the call upstream.
|
|
256
|
+
code:
|
|
257
|
+
isString(event.code) && SERVER_ERROR_CODES.has(event.code)
|
|
258
|
+
? (event.code as VoiceServerErrorCode)
|
|
259
|
+
: 'realtime-failed',
|
|
260
|
+
message: isString(event.message) ? event.message : '',
|
|
261
|
+
retryable: event.retryable === true,
|
|
262
|
+
reference: isString(event.reference) ? event.reference : '',
|
|
263
|
+
...seq,
|
|
264
|
+
};
|
|
265
|
+
case 'session.closed':
|
|
266
|
+
return {
|
|
267
|
+
type: 'session.closed',
|
|
268
|
+
reason:
|
|
269
|
+
isString(event.reason) && CLOSE_REASONS.has(event.reason)
|
|
270
|
+
? (event.reason as VoiceCloseReason)
|
|
271
|
+
: 'error',
|
|
272
|
+
...seq,
|
|
273
|
+
};
|
|
274
|
+
default:
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** `[u8 n][n bytes: item id][PCM16]`, or `null` for a frame that is not one. */
|
|
280
|
+
export function decodeAssistantAudioFrame(
|
|
281
|
+
frame: Uint8Array,
|
|
282
|
+
): { itemId: string; pcm: Uint8Array } | null {
|
|
283
|
+
if (frame.byteLength < 2) return null;
|
|
284
|
+
const length = frame[0]!;
|
|
285
|
+
if (length === 0 || frame.byteLength < 1 + length) return null;
|
|
286
|
+
const itemId = new TextDecoder().decode(frame.subarray(1, 1 + length));
|
|
287
|
+
return { itemId, pcm: frame.subarray(1 + length) };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** The test and dev counterpart: what the server sends. */
|
|
291
|
+
export function encodeAssistantAudioFrame(itemId: string, pcm: Uint8Array): Uint8Array {
|
|
292
|
+
const id = new TextEncoder().encode(itemId);
|
|
293
|
+
const frame = new Uint8Array(1 + id.byteLength + pcm.byteLength);
|
|
294
|
+
frame[0] = id.byteLength;
|
|
295
|
+
frame.set(id, 1);
|
|
296
|
+
frame.set(pcm, 1 + id.byteLength);
|
|
297
|
+
return frame;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** `https://api.alia.onl` → `wss://api.alia.onl/v1/voice/session`. */
|
|
301
|
+
export function voiceSessionUrl(apiUrl: string): string {
|
|
302
|
+
const base = apiUrl.replace(/\/+$/, '');
|
|
303
|
+
const ws = base.startsWith('https://')
|
|
304
|
+
? `wss://${base.slice('https://'.length)}`
|
|
305
|
+
: base.startsWith('http://')
|
|
306
|
+
? `ws://${base.slice('http://'.length)}`
|
|
307
|
+
: base;
|
|
308
|
+
return `${ws}${VOICE_SESSION_PATH}`;
|
|
309
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ComponentType } from 'react';
|
|
2
2
|
import type { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { VoiceErrorCode } from './lib/speech-messages';
|
|
4
|
+
import type { VoiceCloseReason } from './lib/voice-protocol';
|
|
3
5
|
|
|
4
6
|
// ── Suggestion Types ──
|
|
5
7
|
|
|
@@ -74,8 +76,6 @@ export interface ChatMessage {
|
|
|
74
76
|
speaker?: 'primary';
|
|
75
77
|
/** Whether a voice transcript is still streaming */
|
|
76
78
|
isStreaming?: boolean;
|
|
77
|
-
/** Cached TTS audio URL for read-aloud */
|
|
78
|
-
audioUrl?: string;
|
|
79
79
|
/** Delegated agent identity */
|
|
80
80
|
/** `character` is the agent's look as the server stores it (JSON), parsed where it is drawn. */
|
|
81
81
|
agentInfo?: { id: string; name: string; character?: unknown };
|
|
@@ -92,9 +92,43 @@ export interface ToolInvocation {
|
|
|
92
92
|
|
|
93
93
|
// ── Voice Types ──
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
/**
|
|
96
|
+
* The call's connection, coarse: what a bar or a wave needs. `reconnecting`
|
|
97
|
+
* while a dropped socket resumes or Alia re-opens the session upstream.
|
|
98
|
+
*/
|
|
99
|
+
export type RoomState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
|
|
100
|
+
/** Who has the turn, coarse: the palette of the ambient field and the bar's word. */
|
|
96
101
|
export type AgentState = 'idle' | 'listening' | 'thinking' | 'speaking';
|
|
97
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The call's honest state (ADR 0017 §4). Every state is entered on an event
|
|
105
|
+
* that proves it, never on a timer:
|
|
106
|
+
*
|
|
107
|
+
* - `connecting` — socket open → authenticated → `session.start` accepted →
|
|
108
|
+
* the realtime session created upstream (`session.ready`).
|
|
109
|
+
* - `listening` — ONLY once the session is ready, the microphone delivered its
|
|
110
|
+
* first buffer and Alia acknowledged the first appended audio.
|
|
111
|
+
* - `user-speaking` — the server heard speech start.
|
|
112
|
+
* - `thinking` — from the end of the person's speech to the first answer
|
|
113
|
+
* audio or a tool.
|
|
114
|
+
* - `using-tool` — a tool runs in Alia; `tool` is its name, for a label only.
|
|
115
|
+
* - `speaking` — the first answer frame is PLAYING, not merely received.
|
|
116
|
+
* - `reconnecting` — a resume, or Alia re-opening the session upstream.
|
|
117
|
+
* - `ended` — the call is over; `call-moved-elsewhere` is a reason, not an error.
|
|
118
|
+
* - `error` — a typed failure ended it.
|
|
119
|
+
*/
|
|
120
|
+
export type VoiceCallState =
|
|
121
|
+
| { kind: 'idle' }
|
|
122
|
+
| { kind: 'connecting' }
|
|
123
|
+
| { kind: 'listening' }
|
|
124
|
+
| { kind: 'user-speaking' }
|
|
125
|
+
| { kind: 'thinking' }
|
|
126
|
+
| { kind: 'using-tool'; tool: string }
|
|
127
|
+
| { kind: 'speaking' }
|
|
128
|
+
| { kind: 'reconnecting' }
|
|
129
|
+
| { kind: 'ended'; reason: VoiceCloseReason }
|
|
130
|
+
| { kind: 'error'; code: VoiceErrorCode };
|
|
131
|
+
|
|
98
132
|
export interface VoiceToolInvocation {
|
|
99
133
|
toolCallId: string;
|
|
100
134
|
toolName: string;
|
|
@@ -128,6 +162,17 @@ export interface VoiceSessionState {
|
|
|
128
162
|
export interface VoiceSessionProps {
|
|
129
163
|
/** Alia API base URL. */
|
|
130
164
|
apiUrl?: string;
|
|
165
|
+
/**
|
|
166
|
+
* The conversation the call's transcript is stored in. Omitted, each call
|
|
167
|
+
* starts a conversation of its own in the person's Alia history.
|
|
168
|
+
*/
|
|
169
|
+
conversationId?: string;
|
|
170
|
+
/** The agent the call talks to; omitted, Alia. */
|
|
171
|
+
agentId?: string;
|
|
172
|
+
/** Language spoken (BCP-47); omitted, the platform's. */
|
|
173
|
+
locale?: string;
|
|
174
|
+
/** Which of the product's two voices answers. */
|
|
175
|
+
voice?: 'male' | 'female';
|
|
131
176
|
/** Called on every room, agent, or transcript change. */
|
|
132
177
|
onStateChange: (state: VoiceSessionState) => void;
|
|
133
178
|
/**
|
|
@@ -140,6 +185,6 @@ export interface VoiceSessionProps {
|
|
|
140
185
|
/**
|
|
141
186
|
* The voice capability handed to `AliaChatScreen` / `AliaChatSheet`. Pass
|
|
142
187
|
* `VoiceSession` from `@alia.onl/sdk/voice` to enable voice calls; leave it out
|
|
143
|
-
* and the chat is text-only, with
|
|
188
|
+
* and the chat is text-only, with the audio engine absent from the module graph.
|
|
144
189
|
*/
|
|
145
190
|
export type VoiceSessionComponent = ComponentType<VoiceSessionProps>;
|
package/src/voice.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// @alia.onl/sdk/voice — Alia voice surface
|
|
2
|
-
// The
|
|
3
|
-
// ambient wave
|
|
4
|
-
// consumers never compile the call
|
|
2
|
+
// The voice call (speech to speech through Alia's /v1/voice/session and Kaana),
|
|
3
|
+
// its audio engine, audio visualisation, ambient wave and sound effects. Split
|
|
4
|
+
// out of the root entry so text-chat consumers never compile the call or
|
|
5
|
+
// `react-native-audio-api`.
|
|
5
6
|
|
|
6
7
|
// ── Voice components ──
|
|
7
8
|
export { VoiceSession } from './components/voice/VoiceSession';
|
|
@@ -10,20 +11,37 @@ export { VOICE_CONTROLS_LABELS } from './components/voice/VoiceControls';
|
|
|
10
11
|
export type { VoiceControlsLabels, VoiceControlsProps } from './components/voice/VoiceControls';
|
|
11
12
|
|
|
12
13
|
// ── Voice hooks ──
|
|
13
|
-
export { useVoiceRoom } from './hooks/useVoiceRoom';
|
|
14
|
+
export { useVoiceRoom, roomStateOf, agentStateOf } from './hooks/useVoiceRoom';
|
|
14
15
|
export type { UseVoiceRoomOptions } from './hooks/useVoiceRoom';
|
|
15
|
-
export {
|
|
16
|
+
export { VoiceCall } from './lib/voice-call';
|
|
16
17
|
export type {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from './lib/voice-
|
|
18
|
+
VoiceCallOptions,
|
|
19
|
+
VoiceCallSnapshot,
|
|
20
|
+
VoiceSocket,
|
|
21
|
+
VoiceSocketFactory,
|
|
22
|
+
} from './lib/voice-call';
|
|
23
|
+
export { createVoiceAudioEngine, VoiceAudioEngineError } from './lib/voice-audio-engine';
|
|
24
|
+
export type {
|
|
25
|
+
VoiceAudioEngine,
|
|
26
|
+
VoiceAudioEngineErrorCode,
|
|
27
|
+
VoiceAudioEngineHandlers,
|
|
28
|
+
} from './lib/voice-audio-engine-types';
|
|
29
|
+
export {
|
|
30
|
+
VOICE_PROTOCOL_VERSION,
|
|
31
|
+
VOICE_SAMPLE_RATE,
|
|
32
|
+
decodeAssistantAudioFrame,
|
|
33
|
+
encodeAssistantAudioFrame,
|
|
34
|
+
voiceSessionUrl,
|
|
35
|
+
} from './lib/voice-protocol';
|
|
36
|
+
export type {
|
|
37
|
+
VoiceClientEvent,
|
|
38
|
+
VoiceCloseReason,
|
|
39
|
+
VoiceServerErrorCode,
|
|
40
|
+
VoiceServerEvent,
|
|
41
|
+
} from './lib/voice-protocol';
|
|
22
42
|
export type { VoiceLevelSource } from './lib/voice-levels';
|
|
23
43
|
export { VOICE_ERROR_MESSAGES } from './lib/speech-messages';
|
|
24
44
|
export type { VoiceErrorCode } from './lib/speech-messages';
|
|
25
|
-
export { SpeechClipError } from './lib/speech-synthesis';
|
|
26
|
-
export type { SpeechClipErrorCode } from './lib/speech-synthesis';
|
|
27
45
|
export { useAudioLevelMonitor } from './hooks/useAudioLevelMonitor';
|
|
28
46
|
export { useAudioLevels } from './hooks/useAudioLevels';
|
|
29
47
|
export { useAmbientWave } from './hooks/useAmbientWave';
|
|
@@ -40,6 +58,7 @@ export type { SoundName, SoundSources } from './hooks/useSoundEffects';
|
|
|
40
58
|
export type {
|
|
41
59
|
RoomState,
|
|
42
60
|
AgentState,
|
|
61
|
+
VoiceCallState,
|
|
43
62
|
VoiceMessage,
|
|
44
63
|
VoiceToolInvocation,
|
|
45
64
|
VoiceSessionProps,
|