@absolutejs/voice 0.0.22-beta.127 → 0.0.22-beta.129
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/README.md +53 -0
- package/dist/angular/index.js +26 -0
- package/dist/client/actions.d.ts +54 -0
- package/dist/client/htmxBootstrap.js +26 -0
- package/dist/client/index.js +26 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +605 -29
- package/dist/openaiRealtime.d.ts +27 -0
- package/dist/react/index.js +26 -0
- package/dist/svelte/index.js +26 -0
- package/dist/telephony/twilio.d.ts +3 -2
- package/dist/testing/index.js +113 -21
- package/dist/types.d.ts +26 -3
- package/dist/vue/index.js +26 -0
- package/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RealtimeAdapter } from './types';
|
|
2
|
+
export type OpenAIRealtimeModel = 'gpt-realtime' | 'gpt-realtime-mini' | 'gpt-4o-realtime-preview' | 'gpt-4o-mini-realtime-preview' | (string & {});
|
|
3
|
+
export type OpenAIRealtimeVoice = 'alloy' | 'ash' | 'ballad' | 'cedar' | 'coral' | 'echo' | 'marin' | 'sage' | 'shimmer' | 'verse' | {
|
|
4
|
+
id: string;
|
|
5
|
+
} | (string & {});
|
|
6
|
+
export type OpenAIRealtimeTranscriptionModel = 'gpt-4o-mini-transcribe' | 'gpt-4o-transcribe' | 'whisper-1' | (string & {});
|
|
7
|
+
export type OpenAIRealtimeNoiseReduction = 'near_field' | 'far_field';
|
|
8
|
+
export type OpenAIRealtimeResponseMode = 'audio' | 'text';
|
|
9
|
+
export type OpenAIRealtimeAdapterOptions = {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
autoCommitSilenceMs?: number;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
emitResponseTranscripts?: boolean;
|
|
14
|
+
inputTranscriptionLanguage?: string;
|
|
15
|
+
inputTranscriptionModel?: OpenAIRealtimeTranscriptionModel | null;
|
|
16
|
+
inputTranscriptionPrompt?: string;
|
|
17
|
+
instructions?: string;
|
|
18
|
+
maxOutputTokens?: number | 'inf';
|
|
19
|
+
model?: OpenAIRealtimeModel;
|
|
20
|
+
noiseReduction?: OpenAIRealtimeNoiseReduction;
|
|
21
|
+
responseMode?: OpenAIRealtimeResponseMode;
|
|
22
|
+
speed?: number;
|
|
23
|
+
temperature?: number;
|
|
24
|
+
voice?: OpenAIRealtimeVoice;
|
|
25
|
+
webSocket?: typeof WebSocket;
|
|
26
|
+
};
|
|
27
|
+
export declare const createOpenAIRealtimeAdapter: (options: OpenAIRealtimeAdapterOptions) => RealtimeAdapter;
|
package/dist/react/index.js
CHANGED
|
@@ -2567,6 +2567,17 @@ var serverMessageToAction = (message) => {
|
|
|
2567
2567
|
transcript: message.transcript,
|
|
2568
2568
|
type: "partial"
|
|
2569
2569
|
};
|
|
2570
|
+
case "replay":
|
|
2571
|
+
return {
|
|
2572
|
+
assistantTexts: message.assistantTexts,
|
|
2573
|
+
call: message.call,
|
|
2574
|
+
partial: message.partial,
|
|
2575
|
+
scenarioId: message.scenarioId,
|
|
2576
|
+
sessionId: message.sessionId,
|
|
2577
|
+
status: message.status,
|
|
2578
|
+
turns: message.turns,
|
|
2579
|
+
type: "replay"
|
|
2580
|
+
};
|
|
2570
2581
|
case "session":
|
|
2571
2582
|
return {
|
|
2572
2583
|
sessionId: message.sessionId,
|
|
@@ -2631,6 +2642,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
2631
2642
|
case "final":
|
|
2632
2643
|
case "partial":
|
|
2633
2644
|
case "pong":
|
|
2645
|
+
case "replay":
|
|
2634
2646
|
case "session":
|
|
2635
2647
|
case "turn":
|
|
2636
2648
|
return true;
|
|
@@ -2895,6 +2907,20 @@ var createVoiceStreamStore = () => {
|
|
|
2895
2907
|
partial: action.transcript.text
|
|
2896
2908
|
};
|
|
2897
2909
|
break;
|
|
2910
|
+
case "replay":
|
|
2911
|
+
state = {
|
|
2912
|
+
...state,
|
|
2913
|
+
assistantTexts: [...action.assistantTexts],
|
|
2914
|
+
call: action.call ?? null,
|
|
2915
|
+
error: null,
|
|
2916
|
+
isConnected: action.status === "active",
|
|
2917
|
+
partial: action.partial,
|
|
2918
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
2919
|
+
sessionId: action.sessionId,
|
|
2920
|
+
status: action.status,
|
|
2921
|
+
turns: [...action.turns]
|
|
2922
|
+
};
|
|
2923
|
+
break;
|
|
2898
2924
|
case "session":
|
|
2899
2925
|
state = {
|
|
2900
2926
|
...state,
|
package/dist/svelte/index.js
CHANGED
|
@@ -865,6 +865,17 @@ var serverMessageToAction = (message) => {
|
|
|
865
865
|
transcript: message.transcript,
|
|
866
866
|
type: "partial"
|
|
867
867
|
};
|
|
868
|
+
case "replay":
|
|
869
|
+
return {
|
|
870
|
+
assistantTexts: message.assistantTexts,
|
|
871
|
+
call: message.call,
|
|
872
|
+
partial: message.partial,
|
|
873
|
+
scenarioId: message.scenarioId,
|
|
874
|
+
sessionId: message.sessionId,
|
|
875
|
+
status: message.status,
|
|
876
|
+
turns: message.turns,
|
|
877
|
+
type: "replay"
|
|
878
|
+
};
|
|
868
879
|
case "session":
|
|
869
880
|
return {
|
|
870
881
|
sessionId: message.sessionId,
|
|
@@ -929,6 +940,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
929
940
|
case "final":
|
|
930
941
|
case "partial":
|
|
931
942
|
case "pong":
|
|
943
|
+
case "replay":
|
|
932
944
|
case "session":
|
|
933
945
|
case "turn":
|
|
934
946
|
return true;
|
|
@@ -1193,6 +1205,20 @@ var createVoiceStreamStore = () => {
|
|
|
1193
1205
|
partial: action.transcript.text
|
|
1194
1206
|
};
|
|
1195
1207
|
break;
|
|
1208
|
+
case "replay":
|
|
1209
|
+
state = {
|
|
1210
|
+
...state,
|
|
1211
|
+
assistantTexts: [...action.assistantTexts],
|
|
1212
|
+
call: action.call ?? null,
|
|
1213
|
+
error: null,
|
|
1214
|
+
isConnected: action.status === "active",
|
|
1215
|
+
partial: action.partial,
|
|
1216
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
1217
|
+
sessionId: action.sessionId,
|
|
1218
|
+
status: action.status,
|
|
1219
|
+
turns: [...action.turns]
|
|
1220
|
+
};
|
|
1221
|
+
break;
|
|
1196
1222
|
case "session":
|
|
1197
1223
|
state = {
|
|
1198
1224
|
...state,
|
|
@@ -2,7 +2,7 @@ import { Elysia } from 'elysia';
|
|
|
2
2
|
import type { VoiceTelephonySetupStatus, VoiceTelephonySmokeCheck, VoiceTelephonySmokeReport } from './contract';
|
|
3
3
|
import { type VoiceTelephonyOutcomePolicy, type VoiceTelephonyWebhookRoutesOptions } from '../telephonyOutcome';
|
|
4
4
|
import { type VoiceCallReviewArtifact, type VoiceCallReviewConfig } from '../testing/review';
|
|
5
|
-
import type { AudioFormat, VoiceLogger, VoicePluginConfig, VoiceSessionRecord, VoiceServerMessage } from '../types';
|
|
5
|
+
import type { AudioFormat, STTAdapter, VoiceLogger, VoicePluginConfig, VoiceSessionRecord, VoiceServerMessage } from '../types';
|
|
6
6
|
type TwilioMediaPayload = {
|
|
7
7
|
chunk?: string;
|
|
8
8
|
payload: string;
|
|
@@ -78,7 +78,7 @@ export type TwilioMediaStreamSocket = {
|
|
|
78
78
|
close: (code?: number, reason?: string) => void | Promise<void>;
|
|
79
79
|
send: (data: string) => void | Promise<void>;
|
|
80
80
|
};
|
|
81
|
-
export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<VoicePluginConfig<TContext, TSession, TResult>, 'htmx' | 'path'> & {
|
|
81
|
+
export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = Omit<VoicePluginConfig<TContext, TSession, TResult>, 'htmx' | 'path' | 'stt'> & {
|
|
82
82
|
clearOnInboundMedia?: boolean;
|
|
83
83
|
context: TContext;
|
|
84
84
|
logger?: VoiceLogger;
|
|
@@ -97,6 +97,7 @@ export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends
|
|
|
97
97
|
};
|
|
98
98
|
scenarioId?: string;
|
|
99
99
|
sessionId?: string;
|
|
100
|
+
stt: STTAdapter;
|
|
100
101
|
};
|
|
101
102
|
export type TwilioMediaStreamBridge = {
|
|
102
103
|
close: (reason?: string) => Promise<void>;
|
package/dist/testing/index.js
CHANGED
|
@@ -2126,6 +2126,17 @@ var serverMessageToAction = (message) => {
|
|
|
2126
2126
|
transcript: message.transcript,
|
|
2127
2127
|
type: "partial"
|
|
2128
2128
|
};
|
|
2129
|
+
case "replay":
|
|
2130
|
+
return {
|
|
2131
|
+
assistantTexts: message.assistantTexts,
|
|
2132
|
+
call: message.call,
|
|
2133
|
+
partial: message.partial,
|
|
2134
|
+
scenarioId: message.scenarioId,
|
|
2135
|
+
sessionId: message.sessionId,
|
|
2136
|
+
status: message.status,
|
|
2137
|
+
turns: message.turns,
|
|
2138
|
+
type: "replay"
|
|
2139
|
+
};
|
|
2129
2140
|
case "session":
|
|
2130
2141
|
return {
|
|
2131
2142
|
sessionId: message.sessionId,
|
|
@@ -2190,6 +2201,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
2190
2201
|
case "final":
|
|
2191
2202
|
case "partial":
|
|
2192
2203
|
case "pong":
|
|
2204
|
+
case "replay":
|
|
2193
2205
|
case "session":
|
|
2194
2206
|
case "turn":
|
|
2195
2207
|
return true;
|
|
@@ -2454,6 +2466,20 @@ var createVoiceStreamStore = () => {
|
|
|
2454
2466
|
partial: action.transcript.text
|
|
2455
2467
|
};
|
|
2456
2468
|
break;
|
|
2469
|
+
case "replay":
|
|
2470
|
+
state = {
|
|
2471
|
+
...state,
|
|
2472
|
+
assistantTexts: [...action.assistantTexts],
|
|
2473
|
+
call: action.call ?? null,
|
|
2474
|
+
error: null,
|
|
2475
|
+
isConnected: action.status === "active",
|
|
2476
|
+
partial: action.partial,
|
|
2477
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
2478
|
+
sessionId: action.sessionId,
|
|
2479
|
+
status: action.status,
|
|
2480
|
+
turns: [...action.turns]
|
|
2481
|
+
};
|
|
2482
|
+
break;
|
|
2457
2483
|
case "session":
|
|
2458
2484
|
state = {
|
|
2459
2485
|
...state,
|
|
@@ -5033,6 +5059,12 @@ var DEFAULT_FORMAT = {
|
|
|
5033
5059
|
encoding: "pcm_s16le",
|
|
5034
5060
|
sampleRateHz: 16000
|
|
5035
5061
|
};
|
|
5062
|
+
var DEFAULT_REALTIME_FORMAT = {
|
|
5063
|
+
channels: 1,
|
|
5064
|
+
container: "raw",
|
|
5065
|
+
encoding: "pcm_s16le",
|
|
5066
|
+
sampleRateHz: 24000
|
|
5067
|
+
};
|
|
5036
5068
|
var toError = (value) => value instanceof Error ? value : new Error(String(value));
|
|
5037
5069
|
var createEmptyCurrentTurn = () => ({
|
|
5038
5070
|
finalText: "",
|
|
@@ -5310,6 +5342,18 @@ var createVoiceSession = (options) => {
|
|
|
5310
5342
|
type: "call_lifecycle"
|
|
5311
5343
|
});
|
|
5312
5344
|
};
|
|
5345
|
+
const sendReplay = async (session) => {
|
|
5346
|
+
await send({
|
|
5347
|
+
assistantTexts: session.turns.flatMap((turn) => turn.assistantText ? [turn.assistantText] : []),
|
|
5348
|
+
call: session.call,
|
|
5349
|
+
partial: session.currentTurn.partialText,
|
|
5350
|
+
scenarioId: session.scenarioId,
|
|
5351
|
+
sessionId: options.id,
|
|
5352
|
+
status: session.status,
|
|
5353
|
+
turns: session.turns,
|
|
5354
|
+
type: "replay"
|
|
5355
|
+
});
|
|
5356
|
+
};
|
|
5313
5357
|
const runHandoff = async (input) => {
|
|
5314
5358
|
const queuedDelivery = options.handoff?.deliveryQueue ? createVoiceHandoffDeliveryRecord({
|
|
5315
5359
|
action: input.action,
|
|
@@ -5413,6 +5457,23 @@ var createVoiceSession = (options) => {
|
|
|
5413
5457
|
});
|
|
5414
5458
|
}
|
|
5415
5459
|
};
|
|
5460
|
+
const sendAssistantAudio = async (chunk, input) => {
|
|
5461
|
+
const normalizedChunk = chunk instanceof Uint8Array ? new Uint8Array(chunk) : chunk instanceof ArrayBuffer ? new Uint8Array(chunk.slice(0)) : new Uint8Array(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength));
|
|
5462
|
+
await send({
|
|
5463
|
+
chunkBase64: encodeBase64(normalizedChunk),
|
|
5464
|
+
format: input.format,
|
|
5465
|
+
receivedAt: input.receivedAt,
|
|
5466
|
+
turnId: activeTTSTurnId,
|
|
5467
|
+
type: "audio"
|
|
5468
|
+
});
|
|
5469
|
+
if (activeTTSTurnId) {
|
|
5470
|
+
await appendTurnLatencyStage({
|
|
5471
|
+
at: input.receivedAt,
|
|
5472
|
+
stage: "assistant_audio_received",
|
|
5473
|
+
turnId: activeTTSTurnId
|
|
5474
|
+
});
|
|
5475
|
+
}
|
|
5476
|
+
};
|
|
5416
5477
|
const scheduleTurnCommit = (delayMs, reason, reset = true) => {
|
|
5417
5478
|
if (!reset && silenceTimer) {
|
|
5418
5479
|
return;
|
|
@@ -6114,8 +6175,12 @@ var createVoiceSession = (options) => {
|
|
|
6114
6175
|
if (sttSession) {
|
|
6115
6176
|
return sttSession;
|
|
6116
6177
|
}
|
|
6117
|
-
const
|
|
6118
|
-
|
|
6178
|
+
const inputAdapter = options.realtime ?? options.stt;
|
|
6179
|
+
if (!inputAdapter) {
|
|
6180
|
+
throw new Error("Voice session requires either an stt or realtime adapter.");
|
|
6181
|
+
}
|
|
6182
|
+
const openedSession = await inputAdapter.open({
|
|
6183
|
+
format: options.realtime ? options.realtimeInputFormat ?? DEFAULT_REALTIME_FORMAT : DEFAULT_FORMAT,
|
|
6119
6184
|
languageStrategy: options.languageStrategy,
|
|
6120
6185
|
lexicon,
|
|
6121
6186
|
phraseHints,
|
|
@@ -6150,6 +6215,16 @@ var createVoiceSession = (options) => {
|
|
|
6150
6215
|
openedSession.on("close", (event) => {
|
|
6151
6216
|
runAdapterEvent("adapter.close", () => handleClose(event));
|
|
6152
6217
|
});
|
|
6218
|
+
if (options.realtime) {
|
|
6219
|
+
openedSession.on("audio", ({ chunk, format, receivedAt }) => {
|
|
6220
|
+
runAdapterEvent("adapter.audio", async () => {
|
|
6221
|
+
await sendAssistantAudio(chunk, {
|
|
6222
|
+
format,
|
|
6223
|
+
receivedAt
|
|
6224
|
+
});
|
|
6225
|
+
});
|
|
6226
|
+
});
|
|
6227
|
+
}
|
|
6153
6228
|
return openedSession;
|
|
6154
6229
|
};
|
|
6155
6230
|
const ensureTTSSession = async () => {
|
|
@@ -6174,21 +6249,10 @@ var createVoiceSession = (options) => {
|
|
|
6174
6249
|
if (ttsSession !== openedSession) {
|
|
6175
6250
|
return;
|
|
6176
6251
|
}
|
|
6177
|
-
|
|
6178
|
-
await send({
|
|
6179
|
-
chunkBase64: encodeBase64(normalizedChunk),
|
|
6252
|
+
await sendAssistantAudio(chunk, {
|
|
6180
6253
|
format,
|
|
6181
|
-
receivedAt
|
|
6182
|
-
turnId: activeTTSTurnId,
|
|
6183
|
-
type: "audio"
|
|
6254
|
+
receivedAt
|
|
6184
6255
|
});
|
|
6185
|
-
if (activeTTSTurnId) {
|
|
6186
|
-
await appendTurnLatencyStage({
|
|
6187
|
-
at: receivedAt,
|
|
6188
|
-
stage: "assistant_audio_received",
|
|
6189
|
-
turnId: activeTTSTurnId
|
|
6190
|
-
});
|
|
6191
|
-
}
|
|
6192
6256
|
});
|
|
6193
6257
|
});
|
|
6194
6258
|
openedSession.on("error", (event) => {
|
|
@@ -6267,7 +6331,8 @@ var createVoiceSession = (options) => {
|
|
|
6267
6331
|
await appendTrace({
|
|
6268
6332
|
payload: {
|
|
6269
6333
|
text: output.assistantText,
|
|
6270
|
-
ttsConfigured: Boolean(options.tts)
|
|
6334
|
+
ttsConfigured: Boolean(options.tts),
|
|
6335
|
+
realtimeConfigured: Boolean(options.realtime)
|
|
6271
6336
|
},
|
|
6272
6337
|
session,
|
|
6273
6338
|
turnId: turn.id,
|
|
@@ -6299,9 +6364,35 @@ var createVoiceSession = (options) => {
|
|
|
6299
6364
|
turnId: turn.id,
|
|
6300
6365
|
type: "turn.assistant"
|
|
6301
6366
|
});
|
|
6367
|
+
} else if (options.realtime) {
|
|
6368
|
+
const activeRealtimeSession = await ensureAdapter();
|
|
6369
|
+
const realtimeStartedAt = Date.now();
|
|
6370
|
+
activeTTSTurnId = turn.id;
|
|
6371
|
+
await appendTurnLatencyStage({
|
|
6372
|
+
at: realtimeStartedAt,
|
|
6373
|
+
session,
|
|
6374
|
+
stage: "tts_send_started",
|
|
6375
|
+
turnId: turn.id
|
|
6376
|
+
});
|
|
6377
|
+
await activeRealtimeSession.send(output.assistantText);
|
|
6378
|
+
await appendTurnLatencyStage({
|
|
6379
|
+
session,
|
|
6380
|
+
stage: "tts_send_completed",
|
|
6381
|
+
turnId: turn.id
|
|
6382
|
+
});
|
|
6383
|
+
await appendTrace({
|
|
6384
|
+
payload: {
|
|
6385
|
+
elapsedMs: Date.now() - realtimeStartedAt,
|
|
6386
|
+
mode: "realtime",
|
|
6387
|
+
status: "sent"
|
|
6388
|
+
},
|
|
6389
|
+
session,
|
|
6390
|
+
turnId: turn.id,
|
|
6391
|
+
type: "turn.assistant"
|
|
6392
|
+
});
|
|
6302
6393
|
}
|
|
6303
6394
|
} catch (error) {
|
|
6304
|
-
logger.warn("voice
|
|
6395
|
+
logger.warn("voice assistant audio send failed", {
|
|
6305
6396
|
error: toError(error).message,
|
|
6306
6397
|
sessionId: options.id,
|
|
6307
6398
|
turnId: turn.id
|
|
@@ -6309,7 +6400,7 @@ var createVoiceSession = (options) => {
|
|
|
6309
6400
|
await appendTrace({
|
|
6310
6401
|
payload: {
|
|
6311
6402
|
error: toError(error).message,
|
|
6312
|
-
status: "tts-send-failed"
|
|
6403
|
+
status: options.realtime ? "realtime-send-failed" : "tts-send-failed"
|
|
6313
6404
|
},
|
|
6314
6405
|
session,
|
|
6315
6406
|
turnId: turn.id,
|
|
@@ -6514,7 +6605,7 @@ var createVoiceSession = (options) => {
|
|
|
6514
6605
|
turn,
|
|
6515
6606
|
type: "turn"
|
|
6516
6607
|
});
|
|
6517
|
-
if (options.sttLifecycle === "turn-scoped") {
|
|
6608
|
+
if (options.stt && options.sttLifecycle === "turn-scoped") {
|
|
6518
6609
|
await closeAdapter("turn-commit");
|
|
6519
6610
|
}
|
|
6520
6611
|
await completeTurn(updatedSession, turn);
|
|
@@ -6577,6 +6668,7 @@ var createVoiceSession = (options) => {
|
|
|
6577
6668
|
scenarioId: session.scenarioId,
|
|
6578
6669
|
type: "session"
|
|
6579
6670
|
});
|
|
6671
|
+
await sendReplay(session);
|
|
6580
6672
|
if (shouldFireOnSession) {
|
|
6581
6673
|
await options.route.onCallStart?.({
|
|
6582
6674
|
api,
|
|
@@ -9600,7 +9692,7 @@ var runVoiceTelephonyBenchmark = async (scenarios = getDefaultVoiceTelephonyBenc
|
|
|
9600
9692
|
};
|
|
9601
9693
|
};
|
|
9602
9694
|
// src/testing/tts.ts
|
|
9603
|
-
var
|
|
9695
|
+
var DEFAULT_REALTIME_FORMAT2 = {
|
|
9604
9696
|
channels: 1,
|
|
9605
9697
|
container: "raw",
|
|
9606
9698
|
encoding: "pcm_s16le",
|
|
@@ -9659,7 +9751,7 @@ var runTTSAdapterFixture = async (adapter, fixture, options = {}) => {
|
|
|
9659
9751
|
let audioDurationMs = 0;
|
|
9660
9752
|
let audioChunkCount = 0;
|
|
9661
9753
|
const session = adapter.kind === "realtime" ? await adapter.open({
|
|
9662
|
-
format: options.realtimeFormat ??
|
|
9754
|
+
format: options.realtimeFormat ?? DEFAULT_REALTIME_FORMAT2,
|
|
9663
9755
|
sessionId: `tts-benchmark:${fixture.id}`,
|
|
9664
9756
|
...openOptions ?? {}
|
|
9665
9757
|
}) : await adapter.open({
|
package/dist/types.d.ts
CHANGED
|
@@ -616,9 +616,11 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
|
|
|
616
616
|
lexicon?: VoiceLexiconEntry[] | VoiceLexiconResolver<TContext>;
|
|
617
617
|
phraseHints?: VoicePhraseHint[] | VoicePhraseHintResolver<TContext>;
|
|
618
618
|
preset?: VoiceRuntimePreset;
|
|
619
|
-
stt
|
|
619
|
+
stt?: STTAdapter;
|
|
620
620
|
sttFallback?: VoiceSTTFallbackConfig;
|
|
621
621
|
sttLifecycle?: VoiceSTTLifecycle;
|
|
622
|
+
realtime?: RealtimeAdapter;
|
|
623
|
+
realtimeInputFormat?: AudioFormat;
|
|
622
624
|
tts?: TTSAdapter;
|
|
623
625
|
session: VoiceSessionStore<NoInfer<TSession>>;
|
|
624
626
|
reconnect?: VoiceReconnectConfig;
|
|
@@ -635,7 +637,9 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
|
|
|
635
637
|
id: string;
|
|
636
638
|
context: TContext;
|
|
637
639
|
socket: VoiceSocket;
|
|
638
|
-
stt
|
|
640
|
+
stt?: STTAdapter;
|
|
641
|
+
realtime?: RealtimeAdapter;
|
|
642
|
+
realtimeInputFormat?: AudioFormat;
|
|
639
643
|
tts?: TTSAdapter;
|
|
640
644
|
languageStrategy?: VoiceLanguageStrategy;
|
|
641
645
|
lexicon?: VoiceLexiconEntry[];
|
|
@@ -682,6 +686,16 @@ export type VoiceServerSessionMessage = {
|
|
|
682
686
|
status: VoiceSessionStatus;
|
|
683
687
|
scenarioId?: string;
|
|
684
688
|
};
|
|
689
|
+
export type VoiceServerReplayMessage<TResult = unknown> = {
|
|
690
|
+
type: 'replay';
|
|
691
|
+
assistantTexts: string[];
|
|
692
|
+
call?: VoiceCallLifecycleState;
|
|
693
|
+
partial: string;
|
|
694
|
+
scenarioId?: string;
|
|
695
|
+
sessionId: string;
|
|
696
|
+
status: VoiceSessionStatus;
|
|
697
|
+
turns: VoiceTurnRecord<TResult>[];
|
|
698
|
+
};
|
|
685
699
|
export type VoiceServerPartialMessage = {
|
|
686
700
|
type: 'partial';
|
|
687
701
|
transcript: Transcript;
|
|
@@ -723,7 +737,7 @@ export type VoiceServerErrorMessage = {
|
|
|
723
737
|
export type VoiceServerPongMessage = {
|
|
724
738
|
type: 'pong';
|
|
725
739
|
};
|
|
726
|
-
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAudioMessage | VoiceServerCallLifecycleMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage;
|
|
740
|
+
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerReplayMessage<TResult> | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAudioMessage | VoiceServerCallLifecycleMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage;
|
|
727
741
|
export type VoiceConnectionOptions = {
|
|
728
742
|
protocols?: string[];
|
|
729
743
|
scenarioId?: string;
|
|
@@ -974,6 +988,15 @@ export type VoiceStoreAction<TResult = unknown> = {
|
|
|
974
988
|
sessionId: string;
|
|
975
989
|
scenarioId?: string;
|
|
976
990
|
status: VoiceSessionStatus;
|
|
991
|
+
} | {
|
|
992
|
+
type: 'replay';
|
|
993
|
+
assistantTexts: string[];
|
|
994
|
+
call?: VoiceCallLifecycleState;
|
|
995
|
+
partial: string;
|
|
996
|
+
scenarioId?: string;
|
|
997
|
+
sessionId: string;
|
|
998
|
+
status: VoiceSessionStatus;
|
|
999
|
+
turns: VoiceTurnRecord<TResult>[];
|
|
977
1000
|
} | {
|
|
978
1001
|
type: 'call_lifecycle';
|
|
979
1002
|
event: VoiceCallLifecycleEvent;
|
package/dist/vue/index.js
CHANGED
|
@@ -2338,6 +2338,17 @@ var serverMessageToAction = (message) => {
|
|
|
2338
2338
|
transcript: message.transcript,
|
|
2339
2339
|
type: "partial"
|
|
2340
2340
|
};
|
|
2341
|
+
case "replay":
|
|
2342
|
+
return {
|
|
2343
|
+
assistantTexts: message.assistantTexts,
|
|
2344
|
+
call: message.call,
|
|
2345
|
+
partial: message.partial,
|
|
2346
|
+
scenarioId: message.scenarioId,
|
|
2347
|
+
sessionId: message.sessionId,
|
|
2348
|
+
status: message.status,
|
|
2349
|
+
turns: message.turns,
|
|
2350
|
+
type: "replay"
|
|
2351
|
+
};
|
|
2341
2352
|
case "session":
|
|
2342
2353
|
return {
|
|
2343
2354
|
sessionId: message.sessionId,
|
|
@@ -2402,6 +2413,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
2402
2413
|
case "final":
|
|
2403
2414
|
case "partial":
|
|
2404
2415
|
case "pong":
|
|
2416
|
+
case "replay":
|
|
2405
2417
|
case "session":
|
|
2406
2418
|
case "turn":
|
|
2407
2419
|
return true;
|
|
@@ -2666,6 +2678,20 @@ var createVoiceStreamStore = () => {
|
|
|
2666
2678
|
partial: action.transcript.text
|
|
2667
2679
|
};
|
|
2668
2680
|
break;
|
|
2681
|
+
case "replay":
|
|
2682
|
+
state = {
|
|
2683
|
+
...state,
|
|
2684
|
+
assistantTexts: [...action.assistantTexts],
|
|
2685
|
+
call: action.call ?? null,
|
|
2686
|
+
error: null,
|
|
2687
|
+
isConnected: action.status === "active",
|
|
2688
|
+
partial: action.partial,
|
|
2689
|
+
scenarioId: action.scenarioId ?? state.scenarioId,
|
|
2690
|
+
sessionId: action.sessionId,
|
|
2691
|
+
status: action.status,
|
|
2692
|
+
turns: [...action.turns]
|
|
2693
|
+
};
|
|
2694
|
+
break;
|
|
2669
2695
|
case "session":
|
|
2670
2696
|
state = {
|
|
2671
2697
|
...state,
|