@absolutejs/voice 0.0.22-beta.4 → 0.0.22-beta.40
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/angular/index.d.ts +1 -0
- package/dist/angular/index.js +172 -2
- package/dist/angular/voice-provider-status.service.d.ts +12 -0
- package/dist/angular/voice-stream.service.d.ts +2 -0
- package/dist/assistantHealth.d.ts +81 -0
- package/dist/client/actions.d.ts +22 -0
- package/dist/client/connection.d.ts +3 -0
- package/dist/client/htmxBootstrap.js +44 -2
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +125 -2
- package/dist/client/providerStatus.d.ts +19 -0
- package/dist/diagnosticsRoutes.d.ts +44 -0
- package/dist/handoff.d.ts +54 -0
- package/dist/handoffHealth.d.ts +94 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +3431 -128
- package/dist/modelAdapters.d.ts +99 -0
- package/dist/opsWebhook.d.ts +126 -0
- package/dist/providerAdapters.d.ts +37 -0
- package/dist/providerHealth.d.ts +79 -0
- package/dist/qualityRoutes.d.ts +76 -0
- package/dist/queue.d.ts +52 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +148 -2
- package/dist/react/useVoiceController.d.ts +2 -0
- package/dist/react/useVoiceProviderStatus.d.ts +8 -0
- package/dist/react/useVoiceStream.d.ts +2 -0
- package/dist/resilienceRoutes.d.ts +106 -0
- package/dist/sessionReplay.d.ts +175 -0
- package/dist/svelte/createVoiceProviderStatus.d.ts +8 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +127 -2
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1468 -7
- package/dist/testing/ioProviderSimulator.d.ts +41 -0
- package/dist/testing/providerSimulator.d.ts +44 -0
- package/dist/trace.d.ts +1 -1
- package/dist/types.d.ts +84 -2
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.js +161 -2
- package/dist/vue/useVoiceProviderStatus.d.ts +9 -0
- package/dist/vue/useVoiceStream.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { VoiceIOProviderRouterEvent } from '../providerAdapters';
|
|
2
|
+
export type VoiceIOProviderFailureSimulationMode = 'failure' | 'recovery';
|
|
3
|
+
export type VoiceIOProviderFailureSimulationKind = 'stt' | 'tts';
|
|
4
|
+
export type VoiceIOProviderFailureSimulationOperation = 'open' | 'send';
|
|
5
|
+
export type VoiceIOProviderFailureSimulationResult<TProvider extends string = string> = {
|
|
6
|
+
fallbackProvider?: TProvider;
|
|
7
|
+
mode: VoiceIOProviderFailureSimulationMode;
|
|
8
|
+
provider: TProvider;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
status: 'simulated';
|
|
11
|
+
suppressedUntil?: number;
|
|
12
|
+
};
|
|
13
|
+
export type VoiceIOProviderFailureSimulatorOptions<TProvider extends string = string> = {
|
|
14
|
+
cooldownMs?: number;
|
|
15
|
+
fallback?: readonly TProvider[] | ((provider: TProvider) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
16
|
+
failureElapsedMs?: number;
|
|
17
|
+
failureMessage?: (input: {
|
|
18
|
+
kind: VoiceIOProviderFailureSimulationKind;
|
|
19
|
+
operation: VoiceIOProviderFailureSimulationOperation;
|
|
20
|
+
provider: TProvider;
|
|
21
|
+
}) => string;
|
|
22
|
+
kind: VoiceIOProviderFailureSimulationKind;
|
|
23
|
+
latencyBudgets?: Partial<Record<TProvider, number>>;
|
|
24
|
+
now?: () => number;
|
|
25
|
+
onProviderEvent?: (event: VoiceIOProviderRouterEvent<TProvider>, input: {
|
|
26
|
+
mode: VoiceIOProviderFailureSimulationMode;
|
|
27
|
+
provider: TProvider;
|
|
28
|
+
sessionId: string;
|
|
29
|
+
}) => Promise<void> | void;
|
|
30
|
+
operation?: VoiceIOProviderFailureSimulationOperation;
|
|
31
|
+
providers: readonly TProvider[];
|
|
32
|
+
recoveryElapsedMs?: number | Partial<Record<TProvider, number>>;
|
|
33
|
+
sessionId?: (input: {
|
|
34
|
+
mode: VoiceIOProviderFailureSimulationMode;
|
|
35
|
+
now: number;
|
|
36
|
+
provider: TProvider;
|
|
37
|
+
}) => string;
|
|
38
|
+
};
|
|
39
|
+
export declare const createVoiceIOProviderFailureSimulator: <TProvider extends string>(options: VoiceIOProviderFailureSimulatorOptions<TProvider>) => {
|
|
40
|
+
run: (provider: TProvider, mode: VoiceIOProviderFailureSimulationMode) => Promise<VoiceIOProviderFailureSimulationResult<TProvider>>;
|
|
41
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { VoiceAgentModelInput, VoiceAgentModelOutput } from '../agent';
|
|
2
|
+
import type { VoiceSessionRecord } from '../types';
|
|
3
|
+
import type { VoiceProviderRouterEvent, VoiceProviderRouterHealthOptions } from '../modelAdapters';
|
|
4
|
+
export type VoiceProviderFailureSimulationMode = 'failure' | 'recovery';
|
|
5
|
+
export type VoiceProviderFailureSimulationContext<TProvider extends string = string> = {
|
|
6
|
+
query: {
|
|
7
|
+
provider: TProvider;
|
|
8
|
+
recoverProvider?: TProvider;
|
|
9
|
+
simulateFailureProvider?: TProvider;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export type VoiceProviderFailureSimulationResult<TProvider extends string = string, TResult = unknown> = {
|
|
13
|
+
mode: VoiceProviderFailureSimulationMode;
|
|
14
|
+
provider: TProvider;
|
|
15
|
+
replayHref?: string;
|
|
16
|
+
result: VoiceAgentModelOutput<TResult>;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
status: 'simulated';
|
|
19
|
+
turnId: string;
|
|
20
|
+
};
|
|
21
|
+
type ProviderListResolver<TContext, TSession extends VoiceSessionRecord, TProvider extends string> = readonly TProvider[] | ((input: VoiceAgentModelInput<TContext, TSession>) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
22
|
+
export type VoiceProviderFailureSimulatorOptions<TContext extends VoiceProviderFailureSimulationContext<TProvider>, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TProvider extends string = string> = {
|
|
23
|
+
allowProviders?: ProviderListResolver<TContext, TSession, TProvider>;
|
|
24
|
+
fallback?: readonly TProvider[] | ((provider: TProvider, input: VoiceAgentModelInput<TContext, TSession>) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
25
|
+
isProviderError?: (error: unknown, provider: TProvider) => boolean;
|
|
26
|
+
isRateLimitError?: (error: unknown, provider: TProvider) => boolean;
|
|
27
|
+
onProviderEvent?: (event: VoiceProviderRouterEvent<TProvider>, input: VoiceAgentModelInput<TContext, TSession>) => Promise<void> | void;
|
|
28
|
+
providerHealth?: boolean | VoiceProviderRouterHealthOptions;
|
|
29
|
+
providerLabel?: (provider: TProvider) => string;
|
|
30
|
+
providers: readonly TProvider[];
|
|
31
|
+
replayHref?: false | string | ((input: {
|
|
32
|
+
provider: TProvider;
|
|
33
|
+
sessionId: string;
|
|
34
|
+
turnId: string;
|
|
35
|
+
}) => string);
|
|
36
|
+
response?: (input: {
|
|
37
|
+
mode: VoiceProviderFailureSimulationMode;
|
|
38
|
+
provider: TProvider;
|
|
39
|
+
} & VoiceAgentModelInput<TContext, TSession>) => VoiceAgentModelOutput<TResult> | Promise<VoiceAgentModelOutput<TResult>>;
|
|
40
|
+
};
|
|
41
|
+
export declare const createVoiceProviderFailureSimulator: <TProvider extends string, TResult = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TContext extends VoiceProviderFailureSimulationContext<TProvider> = VoiceProviderFailureSimulationContext<TProvider>>(options: VoiceProviderFailureSimulatorOptions<TContext, TSession, TResult, TProvider>) => {
|
|
42
|
+
run: (provider: TProvider, mode: VoiceProviderFailureSimulationMode) => Promise<VoiceProviderFailureSimulationResult<TProvider, TResult>>;
|
|
43
|
+
};
|
|
44
|
+
export {};
|
package/dist/trace.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.lifecycle' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript';
|
|
1
|
+
export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.handoff' | 'call.lifecycle' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn.transcript';
|
|
2
2
|
export type VoiceTraceEvent<TPayload extends Record<string, unknown> = Record<string, unknown>> = {
|
|
3
3
|
at: number;
|
|
4
4
|
id?: string;
|
package/dist/types.d.ts
CHANGED
|
@@ -269,6 +269,65 @@ export type VoiceCallLifecycleState = {
|
|
|
269
269
|
lastEventAt: number;
|
|
270
270
|
startedAt: number;
|
|
271
271
|
};
|
|
272
|
+
export type VoiceHandoffAction = 'escalate' | 'no-answer' | 'transfer' | 'voicemail';
|
|
273
|
+
export type VoiceHandoffStatus = 'delivered' | 'failed' | 'skipped';
|
|
274
|
+
export type VoiceHandoffResult = {
|
|
275
|
+
deliveredAt?: number;
|
|
276
|
+
deliveredTo?: string;
|
|
277
|
+
error?: string;
|
|
278
|
+
metadata?: Record<string, unknown>;
|
|
279
|
+
status: VoiceHandoffStatus;
|
|
280
|
+
};
|
|
281
|
+
export type VoiceHandoffDeliveryQueueStatus = VoiceHandoffStatus | 'pending';
|
|
282
|
+
export type StoredVoiceHandoffDelivery<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
283
|
+
action: VoiceHandoffAction;
|
|
284
|
+
context: TContext;
|
|
285
|
+
createdAt: number;
|
|
286
|
+
deliveredAt?: number;
|
|
287
|
+
deliveries?: Record<string, VoiceHandoffResult & {
|
|
288
|
+
adapterId: string;
|
|
289
|
+
adapterKind?: string;
|
|
290
|
+
}>;
|
|
291
|
+
deliveryAttempts?: number;
|
|
292
|
+
deliveryError?: string;
|
|
293
|
+
deliveryStatus: VoiceHandoffDeliveryQueueStatus;
|
|
294
|
+
id: string;
|
|
295
|
+
metadata?: Record<string, unknown>;
|
|
296
|
+
reason?: string;
|
|
297
|
+
result?: TResult;
|
|
298
|
+
session: TSession;
|
|
299
|
+
sessionId: string;
|
|
300
|
+
target?: string;
|
|
301
|
+
updatedAt: number;
|
|
302
|
+
};
|
|
303
|
+
export type VoiceHandoffDeliveryStore<TDelivery extends StoredVoiceHandoffDelivery = StoredVoiceHandoffDelivery> = {
|
|
304
|
+
get: (id: string) => Promise<TDelivery | undefined> | TDelivery | undefined;
|
|
305
|
+
list: () => Promise<TDelivery[]> | TDelivery[];
|
|
306
|
+
remove: (id: string) => Promise<void> | void;
|
|
307
|
+
set: (id: string, delivery: TDelivery) => Promise<void> | void;
|
|
308
|
+
};
|
|
309
|
+
export type VoiceHandoffInput<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
310
|
+
action: VoiceHandoffAction;
|
|
311
|
+
api: VoiceSessionHandle<TContext, TSession, TResult>;
|
|
312
|
+
context: TContext;
|
|
313
|
+
metadata?: Record<string, unknown>;
|
|
314
|
+
reason?: string;
|
|
315
|
+
result?: TResult;
|
|
316
|
+
session: TSession;
|
|
317
|
+
target?: string;
|
|
318
|
+
};
|
|
319
|
+
export type VoiceHandoffAdapter<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
320
|
+
actions?: VoiceHandoffAction[];
|
|
321
|
+
handoff: (input: VoiceHandoffInput<TContext, TSession, TResult>) => Promise<VoiceHandoffResult> | VoiceHandoffResult;
|
|
322
|
+
id: string;
|
|
323
|
+
kind?: string;
|
|
324
|
+
};
|
|
325
|
+
export type VoiceHandoffConfig<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
326
|
+
adapters: VoiceHandoffAdapter<TContext, TSession, TResult>[];
|
|
327
|
+
deliveryQueue?: VoiceHandoffDeliveryStore<StoredVoiceHandoffDelivery<TContext, TSession, TResult>>;
|
|
328
|
+
enqueueOnly?: boolean;
|
|
329
|
+
failMode?: 'record' | 'throw';
|
|
330
|
+
};
|
|
272
331
|
export type VoiceSessionStore<TSession extends VoiceSessionRecord = VoiceSessionRecord> = SessionStore<TSession, VoiceSessionSummary>;
|
|
273
332
|
export type VoiceLogger = {
|
|
274
333
|
debug?: (message: string, meta?: Record<string, unknown>) => void;
|
|
@@ -567,6 +626,7 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
|
|
|
567
626
|
audioConditioning?: VoiceAudioConditioningConfig;
|
|
568
627
|
logger?: VoiceLogger;
|
|
569
628
|
htmx?: boolean | VoiceHTMXConfig<TSession, NoInfer<TResult>>;
|
|
629
|
+
handoff?: VoiceHandoffConfig<TContext, TSession, TResult>;
|
|
570
630
|
ops?: VoiceRuntimeOpsConfig<TContext, TSession, TResult>;
|
|
571
631
|
trace?: VoiceTraceEventStore;
|
|
572
632
|
} & VoiceRouteConfig<TContext, TSession, TResult>;
|
|
@@ -588,6 +648,7 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
|
|
|
588
648
|
sttLifecycle: VoiceSTTLifecycle;
|
|
589
649
|
turnDetection: VoiceResolvedTurnDetectionConfig;
|
|
590
650
|
audioConditioning?: VoiceResolvedAudioConditioningConfig;
|
|
651
|
+
handoff?: VoiceHandoffConfig<TContext, TSession, TResult>;
|
|
591
652
|
route: VoiceNormalizedRouteConfig<TContext, TSession, TResult>;
|
|
592
653
|
logger?: VoiceLogger;
|
|
593
654
|
};
|
|
@@ -604,10 +665,17 @@ export type VoiceClientCloseMessage = {
|
|
|
604
665
|
type: 'close';
|
|
605
666
|
reason?: string;
|
|
606
667
|
};
|
|
668
|
+
export type VoiceClientCallControlMessage = {
|
|
669
|
+
type: 'call_control';
|
|
670
|
+
action: 'complete' | 'escalate' | 'no-answer' | 'transfer' | 'voicemail';
|
|
671
|
+
metadata?: Record<string, unknown>;
|
|
672
|
+
reason?: string;
|
|
673
|
+
target?: string;
|
|
674
|
+
};
|
|
607
675
|
export type VoiceClientPingMessage = {
|
|
608
676
|
type: 'ping';
|
|
609
677
|
};
|
|
610
|
-
export type VoiceClientMessage = VoiceClientStartMessage | VoiceClientEndTurnMessage | VoiceClientCloseMessage | VoiceClientPingMessage;
|
|
678
|
+
export type VoiceClientMessage = VoiceClientStartMessage | VoiceClientEndTurnMessage | VoiceClientCloseMessage | VoiceClientCallControlMessage | VoiceClientPingMessage;
|
|
611
679
|
export type VoiceServerSessionMessage = {
|
|
612
680
|
type: 'session';
|
|
613
681
|
sessionId: string;
|
|
@@ -642,6 +710,11 @@ export type VoiceServerCompleteMessage = {
|
|
|
642
710
|
type: 'complete';
|
|
643
711
|
sessionId: string;
|
|
644
712
|
};
|
|
713
|
+
export type VoiceServerCallLifecycleMessage = {
|
|
714
|
+
type: 'call_lifecycle';
|
|
715
|
+
event: VoiceCallLifecycleEvent;
|
|
716
|
+
sessionId: string;
|
|
717
|
+
};
|
|
645
718
|
export type VoiceServerErrorMessage = {
|
|
646
719
|
type: 'error';
|
|
647
720
|
message: string;
|
|
@@ -650,7 +723,7 @@ export type VoiceServerErrorMessage = {
|
|
|
650
723
|
export type VoiceServerPongMessage = {
|
|
651
724
|
type: 'pong';
|
|
652
725
|
};
|
|
653
|
-
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAudioMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage;
|
|
726
|
+
export type VoiceServerMessage<TResult = unknown> = VoiceServerSessionMessage | VoiceServerPartialMessage | VoiceServerFinalMessage | VoiceServerTurnMessage<TResult> | VoiceServerAssistantMessage | VoiceServerAudioMessage | VoiceServerCallLifecycleMessage | VoiceServerCompleteMessage | VoiceServerErrorMessage | VoiceServerPongMessage;
|
|
654
727
|
export type VoiceConnectionOptions = {
|
|
655
728
|
protocols?: string[];
|
|
656
729
|
scenarioId?: string;
|
|
@@ -728,6 +801,7 @@ export type VoiceHTMXOptions<TSession extends VoiceSessionRecord = VoiceSessionR
|
|
|
728
801
|
};
|
|
729
802
|
export type VoiceHTMXConfig<TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = VoiceHTMXRenderer<TSession, TResult> | VoiceHTMXOptions<TSession, TResult>;
|
|
730
803
|
export type VoiceStreamState<TResult = unknown> = {
|
|
804
|
+
call: VoiceCallLifecycleState | null;
|
|
731
805
|
sessionId: string | null;
|
|
732
806
|
scenarioId: string | null;
|
|
733
807
|
status: VoiceSessionStatus | 'idle';
|
|
@@ -744,6 +818,8 @@ export type VoiceStreamState<TResult = unknown> = {
|
|
|
744
818
|
isConnected: boolean;
|
|
745
819
|
};
|
|
746
820
|
export type VoiceStream<TResult = unknown> = {
|
|
821
|
+
call: VoiceCallLifecycleState | null;
|
|
822
|
+
callControl: (message: Omit<VoiceClientCallControlMessage, 'type'>) => void;
|
|
747
823
|
close: () => void;
|
|
748
824
|
start: (input?: {
|
|
749
825
|
scenarioId?: string;
|
|
@@ -810,6 +886,8 @@ export type VoiceBargeInBinding = {
|
|
|
810
886
|
};
|
|
811
887
|
export type VoiceController<TResult = unknown> = {
|
|
812
888
|
bindHTMX: (options: VoiceHTMXBindingOptions) => () => void;
|
|
889
|
+
call: VoiceCallLifecycleState | null;
|
|
890
|
+
callControl: (message: Omit<VoiceClientCallControlMessage, 'type'>) => void;
|
|
813
891
|
close: () => void;
|
|
814
892
|
endTurn: () => void;
|
|
815
893
|
start: (input?: {
|
|
@@ -855,6 +933,10 @@ export type VoiceStoreAction<TResult = unknown> = {
|
|
|
855
933
|
sessionId: string;
|
|
856
934
|
scenarioId?: string;
|
|
857
935
|
status: VoiceSessionStatus;
|
|
936
|
+
} | {
|
|
937
|
+
type: 'call_lifecycle';
|
|
938
|
+
event: VoiceCallLifecycleEvent;
|
|
939
|
+
sessionId: string;
|
|
858
940
|
} | {
|
|
859
941
|
type: 'partial';
|
|
860
942
|
transcript: Transcript;
|
package/dist/vue/index.d.ts
CHANGED
package/dist/vue/index.js
CHANGED
|
@@ -120,6 +120,12 @@ var serverMessageToAction = (message) => {
|
|
|
120
120
|
sessionId: message.sessionId,
|
|
121
121
|
type: "complete"
|
|
122
122
|
};
|
|
123
|
+
case "call_lifecycle":
|
|
124
|
+
return {
|
|
125
|
+
event: message.event,
|
|
126
|
+
sessionId: message.sessionId,
|
|
127
|
+
type: "call_lifecycle"
|
|
128
|
+
};
|
|
123
129
|
case "error":
|
|
124
130
|
return {
|
|
125
131
|
message: normalizeErrorMessage(message.message),
|
|
@@ -163,7 +169,7 @@ var DEFAULT_SCENARIO_QUERY_PARAM = "scenarioId";
|
|
|
163
169
|
var noop = () => {};
|
|
164
170
|
var noopUnsubscribe = () => noop;
|
|
165
171
|
var NOOP_CONNECTION = {
|
|
166
|
-
|
|
172
|
+
callControl: noop,
|
|
167
173
|
close: noop,
|
|
168
174
|
endTurn: noop,
|
|
169
175
|
getReadyState: () => WS_CLOSED,
|
|
@@ -171,6 +177,7 @@ var NOOP_CONNECTION = {
|
|
|
171
177
|
getSessionId: () => "",
|
|
172
178
|
send: noop,
|
|
173
179
|
sendAudio: noop,
|
|
180
|
+
start: () => {},
|
|
174
181
|
subscribe: noopUnsubscribe
|
|
175
182
|
};
|
|
176
183
|
var createSessionId = () => crypto.randomUUID();
|
|
@@ -192,6 +199,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
192
199
|
switch (value.type) {
|
|
193
200
|
case "audio":
|
|
194
201
|
case "assistant":
|
|
202
|
+
case "call_lifecycle":
|
|
195
203
|
case "complete":
|
|
196
204
|
case "error":
|
|
197
205
|
case "final":
|
|
@@ -332,6 +340,12 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
332
340
|
const endTurn = () => {
|
|
333
341
|
send({ type: "end_turn" });
|
|
334
342
|
};
|
|
343
|
+
const callControl = (message) => {
|
|
344
|
+
send({
|
|
345
|
+
...message,
|
|
346
|
+
type: "call_control"
|
|
347
|
+
});
|
|
348
|
+
};
|
|
335
349
|
const close = () => {
|
|
336
350
|
clearTimers();
|
|
337
351
|
if (state.ws) {
|
|
@@ -349,7 +363,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
349
363
|
};
|
|
350
364
|
connect();
|
|
351
365
|
return {
|
|
352
|
-
|
|
366
|
+
callControl,
|
|
353
367
|
close,
|
|
354
368
|
endTurn,
|
|
355
369
|
getReadyState: () => state.ws?.readyState ?? WS_CLOSED,
|
|
@@ -357,6 +371,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
357
371
|
getSessionId: () => state.sessionId,
|
|
358
372
|
send,
|
|
359
373
|
sendAudio,
|
|
374
|
+
start,
|
|
360
375
|
subscribe
|
|
361
376
|
};
|
|
362
377
|
};
|
|
@@ -365,6 +380,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
365
380
|
var createInitialState = () => ({
|
|
366
381
|
assistantAudio: [],
|
|
367
382
|
assistantTexts: [],
|
|
383
|
+
call: null,
|
|
368
384
|
error: null,
|
|
369
385
|
isConnected: false,
|
|
370
386
|
scenarioId: null,
|
|
@@ -408,6 +424,20 @@ var createVoiceStreamStore = () => {
|
|
|
408
424
|
status: "completed"
|
|
409
425
|
};
|
|
410
426
|
break;
|
|
427
|
+
case "call_lifecycle":
|
|
428
|
+
state = {
|
|
429
|
+
...state,
|
|
430
|
+
call: {
|
|
431
|
+
...state.call,
|
|
432
|
+
disposition: action.event.type === "end" ? action.event.disposition : state.call?.disposition,
|
|
433
|
+
endedAt: action.event.type === "end" ? action.event.at : state.call?.endedAt,
|
|
434
|
+
events: [...state.call?.events ?? [], action.event],
|
|
435
|
+
lastEventAt: action.event.at,
|
|
436
|
+
startedAt: state.call?.startedAt ?? action.event.at
|
|
437
|
+
},
|
|
438
|
+
sessionId: action.sessionId
|
|
439
|
+
};
|
|
440
|
+
break;
|
|
411
441
|
case "connected":
|
|
412
442
|
state = {
|
|
413
443
|
...state,
|
|
@@ -494,6 +524,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
494
524
|
}
|
|
495
525
|
});
|
|
496
526
|
return {
|
|
527
|
+
callControl(message) {
|
|
528
|
+
connection.callControl(message);
|
|
529
|
+
},
|
|
497
530
|
close() {
|
|
498
531
|
unsubscribeConnection();
|
|
499
532
|
connection.close();
|
|
@@ -537,6 +570,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
537
570
|
get assistantAudio() {
|
|
538
571
|
return store.getSnapshot().assistantAudio;
|
|
539
572
|
},
|
|
573
|
+
get call() {
|
|
574
|
+
return store.getSnapshot().call;
|
|
575
|
+
},
|
|
540
576
|
sendAudio(audio) {
|
|
541
577
|
connection.sendAudio(audio);
|
|
542
578
|
},
|
|
@@ -554,6 +590,7 @@ var useVoiceStream = (path, options = {}) => {
|
|
|
554
590
|
const stream = createVoiceStream(path, options);
|
|
555
591
|
const assistantAudio = shallowRef([]);
|
|
556
592
|
const assistantTexts = shallowRef([]);
|
|
593
|
+
const call = shallowRef(null);
|
|
557
594
|
const error = ref(null);
|
|
558
595
|
const isConnected = ref(false);
|
|
559
596
|
const partial = ref("");
|
|
@@ -563,6 +600,7 @@ var useVoiceStream = (path, options = {}) => {
|
|
|
563
600
|
const sync = () => {
|
|
564
601
|
assistantAudio.value = [...stream.assistantAudio];
|
|
565
602
|
assistantTexts.value = [...stream.assistantTexts];
|
|
603
|
+
call.value = stream.call;
|
|
566
604
|
error.value = stream.error;
|
|
567
605
|
isConnected.value = stream.isConnected;
|
|
568
606
|
partial.value = stream.partial;
|
|
@@ -580,6 +618,8 @@ var useVoiceStream = (path, options = {}) => {
|
|
|
580
618
|
return {
|
|
581
619
|
assistantAudio,
|
|
582
620
|
assistantTexts,
|
|
621
|
+
call,
|
|
622
|
+
callControl: (message) => stream.callControl(message),
|
|
583
623
|
close: () => destroy(),
|
|
584
624
|
endTurn: () => stream.endTurn(),
|
|
585
625
|
error,
|
|
@@ -1056,6 +1096,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
|
|
|
1056
1096
|
var createInitialState2 = (stream) => ({
|
|
1057
1097
|
assistantAudio: [...stream.assistantAudio],
|
|
1058
1098
|
assistantTexts: [...stream.assistantTexts],
|
|
1099
|
+
call: stream.call,
|
|
1059
1100
|
error: stream.error,
|
|
1060
1101
|
isConnected: stream.isConnected,
|
|
1061
1102
|
isRecording: false,
|
|
@@ -1085,6 +1126,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1085
1126
|
...state,
|
|
1086
1127
|
assistantAudio: [...stream.assistantAudio],
|
|
1087
1128
|
assistantTexts: [...stream.assistantTexts],
|
|
1129
|
+
call: stream.call,
|
|
1088
1130
|
error: stream.error,
|
|
1089
1131
|
isConnected: stream.isConnected,
|
|
1090
1132
|
partial: stream.partial,
|
|
@@ -1162,6 +1204,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1162
1204
|
bindHTMX(bindingOptions) {
|
|
1163
1205
|
return bindVoiceHTMX(stream, bindingOptions);
|
|
1164
1206
|
},
|
|
1207
|
+
callControl: (message) => stream.callControl(message),
|
|
1165
1208
|
close,
|
|
1166
1209
|
endTurn: () => stream.endTurn(),
|
|
1167
1210
|
get error() {
|
|
@@ -1214,6 +1257,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1214
1257
|
},
|
|
1215
1258
|
get assistantAudio() {
|
|
1216
1259
|
return state.assistantAudio;
|
|
1260
|
+
},
|
|
1261
|
+
get call() {
|
|
1262
|
+
return state.call;
|
|
1217
1263
|
}
|
|
1218
1264
|
};
|
|
1219
1265
|
};
|
|
@@ -1270,7 +1316,120 @@ var useVoiceController = (path, options = {}) => {
|
|
|
1270
1316
|
turns
|
|
1271
1317
|
};
|
|
1272
1318
|
};
|
|
1319
|
+
// src/vue/useVoiceProviderStatus.ts
|
|
1320
|
+
import { onUnmounted as onUnmounted3, ref as ref3, shallowRef as shallowRef3 } from "vue";
|
|
1321
|
+
|
|
1322
|
+
// src/client/providerStatus.ts
|
|
1323
|
+
var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
|
|
1324
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1325
|
+
const response = await fetchImpl(path);
|
|
1326
|
+
if (!response.ok) {
|
|
1327
|
+
throw new Error(`Voice provider status failed: HTTP ${response.status}`);
|
|
1328
|
+
}
|
|
1329
|
+
return await response.json();
|
|
1330
|
+
};
|
|
1331
|
+
var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {}) => {
|
|
1332
|
+
const listeners = new Set;
|
|
1333
|
+
let closed = false;
|
|
1334
|
+
let timer;
|
|
1335
|
+
let snapshot = {
|
|
1336
|
+
error: null,
|
|
1337
|
+
isLoading: false,
|
|
1338
|
+
providers: []
|
|
1339
|
+
};
|
|
1340
|
+
const emit = () => {
|
|
1341
|
+
for (const listener of listeners) {
|
|
1342
|
+
listener();
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
const refresh = async () => {
|
|
1346
|
+
if (closed) {
|
|
1347
|
+
return snapshot.providers;
|
|
1348
|
+
}
|
|
1349
|
+
snapshot = {
|
|
1350
|
+
...snapshot,
|
|
1351
|
+
error: null,
|
|
1352
|
+
isLoading: true
|
|
1353
|
+
};
|
|
1354
|
+
emit();
|
|
1355
|
+
try {
|
|
1356
|
+
const providers = await fetchVoiceProviderStatus(path, options);
|
|
1357
|
+
snapshot = {
|
|
1358
|
+
error: null,
|
|
1359
|
+
isLoading: false,
|
|
1360
|
+
providers,
|
|
1361
|
+
updatedAt: Date.now()
|
|
1362
|
+
};
|
|
1363
|
+
emit();
|
|
1364
|
+
return providers;
|
|
1365
|
+
} catch (error) {
|
|
1366
|
+
snapshot = {
|
|
1367
|
+
...snapshot,
|
|
1368
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1369
|
+
isLoading: false
|
|
1370
|
+
};
|
|
1371
|
+
emit();
|
|
1372
|
+
throw error;
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
const close = () => {
|
|
1376
|
+
closed = true;
|
|
1377
|
+
if (timer) {
|
|
1378
|
+
clearInterval(timer);
|
|
1379
|
+
timer = undefined;
|
|
1380
|
+
}
|
|
1381
|
+
listeners.clear();
|
|
1382
|
+
};
|
|
1383
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
1384
|
+
timer = setInterval(() => {
|
|
1385
|
+
refresh().catch(() => {});
|
|
1386
|
+
}, options.intervalMs);
|
|
1387
|
+
}
|
|
1388
|
+
return {
|
|
1389
|
+
close,
|
|
1390
|
+
getServerSnapshot: () => snapshot,
|
|
1391
|
+
getSnapshot: () => snapshot,
|
|
1392
|
+
refresh,
|
|
1393
|
+
subscribe: (listener) => {
|
|
1394
|
+
listeners.add(listener);
|
|
1395
|
+
return () => {
|
|
1396
|
+
listeners.delete(listener);
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
// src/vue/useVoiceProviderStatus.ts
|
|
1403
|
+
var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
|
|
1404
|
+
const store = createVoiceProviderStatusStore(path, options);
|
|
1405
|
+
const error = ref3(null);
|
|
1406
|
+
const isLoading = ref3(false);
|
|
1407
|
+
const providers = shallowRef3([]);
|
|
1408
|
+
const updatedAt = ref3(undefined);
|
|
1409
|
+
const sync = () => {
|
|
1410
|
+
const snapshot = store.getSnapshot();
|
|
1411
|
+
error.value = snapshot.error;
|
|
1412
|
+
isLoading.value = snapshot.isLoading;
|
|
1413
|
+
providers.value = [...snapshot.providers];
|
|
1414
|
+
updatedAt.value = snapshot.updatedAt;
|
|
1415
|
+
};
|
|
1416
|
+
const unsubscribe = store.subscribe(sync);
|
|
1417
|
+
sync();
|
|
1418
|
+
store.refresh().catch(() => {});
|
|
1419
|
+
onUnmounted3(() => {
|
|
1420
|
+
unsubscribe();
|
|
1421
|
+
store.close();
|
|
1422
|
+
});
|
|
1423
|
+
return {
|
|
1424
|
+
error,
|
|
1425
|
+
isLoading,
|
|
1426
|
+
providers,
|
|
1427
|
+
refresh: store.refresh,
|
|
1428
|
+
updatedAt
|
|
1429
|
+
};
|
|
1430
|
+
};
|
|
1273
1431
|
export {
|
|
1274
1432
|
useVoiceStream,
|
|
1433
|
+
useVoiceProviderStatus,
|
|
1275
1434
|
useVoiceController
|
|
1276
1435
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type VoiceProviderStatusClientOptions } from '../client/providerStatus';
|
|
2
|
+
import type { VoiceProviderHealthSummary } from '../providerHealth';
|
|
3
|
+
export declare const useVoiceProviderStatus: <TProvider extends string = string>(path?: string, options?: VoiceProviderStatusClientOptions) => {
|
|
4
|
+
error: import("vue").Ref<string | null, string | null>;
|
|
5
|
+
isLoading: import("vue").Ref<boolean, boolean>;
|
|
6
|
+
providers: import("vue").ShallowRef<VoiceProviderHealthSummary<TProvider>[], VoiceProviderHealthSummary<TProvider>[]>;
|
|
7
|
+
refresh: () => Promise<VoiceProviderHealthSummary<TProvider>[]>;
|
|
8
|
+
updatedAt: import("vue").Ref<number | undefined, number | undefined>;
|
|
9
|
+
};
|
|
@@ -12,6 +12,8 @@ export declare const useVoiceStream: <TResult = unknown>(path: string, options?:
|
|
|
12
12
|
turnId?: string;
|
|
13
13
|
}[]>;
|
|
14
14
|
assistantTexts: import("vue").ShallowRef<string[], string[]>;
|
|
15
|
+
call: import("vue").ShallowRef<import("..").VoiceCallLifecycleState | null, import("..").VoiceCallLifecycleState | null>;
|
|
16
|
+
callControl: (message: Parameters<(message: Omit<import("..").VoiceClientCallControlMessage, "type">) => void>[0]) => void;
|
|
15
17
|
close: () => void;
|
|
16
18
|
endTurn: () => void;
|
|
17
19
|
error: import("vue").Ref<string | null, string | null>;
|